In Java,
"Up-casting is casting to a supertype, while downcasting is casting to
a subtype. Supercasting is always allowed, but subcasting involves a
type check and can throw a ClassCastException."
(What is the difference between up-casting and down-casting with respect to class variable)
Is upcasting also always allowed in C#?
Yes, it is allowed, since a subclass is a particularization of the ancestor class.
Example:
Let us consider the case when we have a class called Bird, another called Sparrow and a third one Eagle. Sparrow and Eagle are inherited from Bird. Sparrows differ from Eagles greatly, but they are Birds. So, if you want to have a Collection of Birds for some reason, then you can have Eagle and Sparrow objects in that Collection at the same time, since they are still Birds, if only specific Birds.
yes, up-casting is allowed :-)
Casting and Type Conversions (C# Programming Guide)
OOP principles state that you can always upcast; however, unlike Java with very restricted number of primitive classes, .Net implementation allows to declare struct types, some of them are weird counter-examples with boxing:
TypedReference reference = new TypedReference();
// Compile time error here! Even if Object is the base type for all types
Object o = (Object)reference;
Technically, TypedReference is an Object:
Object
ValueType
TypedReference
you can easily check it:
Console.Write(typeof(TypedReference).BaseType.BaseType == typeof(Object)
? "TypedReference derived from Object via ValueType"
: "Very strange");
but in order to be represented as Object instance (via cast) it should be boxed which can't be done.
Related
The Java Language Specification says:
An object is a class instance or an array.
And it also says:
arrays [...] may be assigned to variables of type Object
But the part that confuses me is:
The class Object is a superclass of all other classes
If arrays may be assigned to variables of type Object, then it must mean that arrays can be Objects (not only behave as, but to be instead). Then it means that an array is a class instance, which does not seem to be consistent with the first quote (if it were, then why would it be listed as a different thing?).
How can all this fit together?
There is no contradiction.
An array is also an Object, albeit a special kind of Object.
It is like saying: An bird is also an animal, albeit a special kind of animal.
You can convince yourself by compiling and running the following Java code.
String[] arrayOfStrings = { "bla", "blah" };
// examine the class hierarchy of the array
System.out.println("arrayOfStrings is of type "
+ arrayOfStrings.getClass().getSimpleName()
+ " which extends from "
+ arrayOfStrings.getClass().getSuperclass().getSimpleName());
// assingning the array to a variable of type Object
Object object = arrayOfStrings;
The output will be
arrayOfStrings is of type String[] which extends from Object
Arrays are special classes provided to you by Java itself. All of them inherit from common superclass Object. As they inherit from Object they of course can be used anywhere where Object is expected. Instances of arrays are indeed instances of those classes. One can even reference array classes as they do with other classes' literals:
Class<int[]> intArrayClass = int[].class;
I see no conflict.
This can be useful https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html#jls-10.8
Yes... and no. It is true, indeed, that new Object[100] instanceof Object → true, but this is missing the true nature of arrays in Java. Arrays are objects (lowercase), but not Objects (capitalized). Being objects, for example, you have to use the new operator to allocate space for them.
However, the Java Language Specification is right to say that "An object is a class instance or an array", because arrays are fundamentally different from a regular Object. They are inherited from languages such as C++, that were much more deeply rooted in the low-level architecture of computers.
"arrays [...] may be assigned to variables of type Object" only because Java provides an interface for us, programmers, to refer to arrays as Objects. In fact, the JLS says:
All methods of class Object may be invoked on an array
Which of course is true, but it does not logically imply they are Objects. Arrays are not true Objects; therefore, they are not true class instances, and therefore the sentence "The class Object is a superclass of all other classes" doesn't apply here.
All in all, Java is not a pure Object-Oriented programming language (primitives are not objects, for example, but they are nonetheless present in Java). And arrays are a language feature that Java includes that behave as if they were class instances of the Object class, but are not actually class instances of it.
[This is my attempt at summarising the main points made here. Thanks a lot to all of you for your ideas, and feel free to add more!]
The class Object is a superclass of all other classes
All classes in Java extend Object. The class name is actually Object (proper name capitalized). It's why all classes have the method toString() and hashCode(), because they all inherited it from Object.class
An object is a class instance or an array.
An object (lowercase, not a proper name) is the instance generated by the new keyword. ie: File is a class and when you call new File() you just made a File object. I honestly think they should have called it a class instance. (clarification: I wish they never called an instance an object)
arrays [...] may be assigned to variables of type Object
Object[] is an array that can contain instances of type Object.
Object[] obj = new Object[100];
obj instanceof Object evaluates to true.
Your second link also says:
All methods of class Object may be invoked on an array.
So from a dev's POV, at least, it's an Object though there is no java.lang.Array (that is exposed to us) it has been instanced from.
A second indication is that arrays are also stored on the heap.
Java lesson on generics are leading me to variance concept. This causes me some headaches as I cannot find a very simple demonstration of what it is.
I have read several similar questions on stackoverflow, but I found them too difficult to understand for a Java learner. Actually the problem is that the explanation of generics requires variance to be understood, and the concept of variance is demonstrated relying heavily on generics understanding.
I had some hope reading this, but in the end I shared C. R.'s feeling:
The title reminds me of the days learning general relativity. – C.R.
Dec 22 '13 at 7:34
Four theory questions are very confusing to me, and I cannot find good and simple explanations. Here they are, with my current partial understanding (I fear experts will have a great fun reading this).
Your help to correct and clarify is welcome (remember this is for beginners, not for experts).
Is there something wrong with this understanding?
What is invariance / covariance / contravariance related to in the context of programing? My best guess is that:
This is something encountered in object-oriented programing.
This has to do when looking at method arguments and result type in the class and an ancestor.
This is used in the context of method overriding and overloading.
This is used to establish a connection between the type of a method argument, or the method return type, and the inheritance of the classes themselves, e.g. if class D is a descendant of class A, what can we say about the types of arguments and the method method return type?
How variance relates to Java methods? My best guess is that, given two classes A and D, with A being an ancestor of D, and a overhiden/overloaded method f(arg):
If the relation between the argument type in the two methods IS THE SAME than the relation between the two classes, the argument type in the method is said COVARIANT with the class type, said otherwise: the inheritance between arg types in A and D is covariant with the inheritance of classes A and D.
If the relation between the arguments REVERSES the relation between classes, the arg type is said CONTRAVARIANT to the class type, said otherwise: the inheritance between arg types in A and D is contravariant with the inheritance of classes A and D..
Why is variance understanding so important for Java programmers? My guess is that:
Java language creators have implemented rules for variance in the language, and this has implications on what a programmer can do.
A rule states that the return type of an overriding/overloading method must be contravariant to the inheritance.
Another rule states that the type of an argument of an overriding/overloading must be is covariant to the inheritance.
The Java compiler checks the variance rules are valid, and provides errors or warnings accordingly. Deciphering the messages is easier with variance knowledge.
What is the difference between overrhiding and overloading? Best guess:
A method overrides another method when argument and return types are both invariant. All other cases are understood by the compiler as overloading.
This is not specific to OO, but has to do with the properties of certain types.
For example, with the function type
A -> B // functional notation
public B meth(A arg) // how this looks in Java
we have the following:
Let C be a subtype of A, and D be a subtype of B. Then the following is valid:
B b = meth(new C()); // B >= B, C < A
Object o = meth(new C()); // Object > B, C < A
but the follwoing are invalid:
D d = meth(new A()); // because D < B
B b = meth(new Object()); // because Object > A
hence, to check whether a call of meth is valid, we must check
The expected return type is a supertype of the declared return type.
The actual argument type is a subtype of the declared argument type.
This is all well known and intuitive. By convention we say that the return type of a function is covariant, and the argument type of a method is contravariant.
With parameterized types, like List, we have it that the argument type is invariant in languages like Java, where we have mutability. We can't say that a list of C's is a list of A's, because, if it were so, we could store an A in a list of Cs, much to the surprise of the caller, who assumes only Cs in the list. However, in languages where values are immutable, like Haskell, this is not a problem. Because the data we pass to functions cannot be mutated, a list of C actually is a list of A if C is a subtype of A. (Note that Haskell has no real subtyping, but has instead the related notion of "more/less polymorphic" types.)
Basically what the title says, but some elaboration. I have a SuperClass with a couple of SubClasses. I needed an ArrayList to hold both types of Subclasses so hence the ArrayList of type SuperClass. I tried to access Subclass1's getQuantity() method using ArrayList.get(0).getQuantity(); (assuming that index 0 is of type SubClass1). I get the error: getQuantity is undefined for the type SuperClass.
Do the SubClass objects not keep their properties when put into a SuperClass ArrayList? And if they do keep their properties, how do I access them?
The objects themselves are still a subclass, but when you get them out of the collection it only knows about the superclass so it can't tell you which is which, it has to pick the common denominator.
If you know exactly that a specific index holds an object of type Subclass you can just cast it:
Subclass myObject = (Subclass) list.get(0);
System.out.println(myObject.getQuantity());
And it should work.
And a safer way requires testing if the object is really what you think it is:
SuperClass myObject = list.get(0);
if ( myObject instanceof Subclass) {
Subclass mySubObject = (Subclass) myObject;
System.out.println(mySubObject.getQuantity());
}
The first example raises an exception if the object is not of type Subclass, the second one wouldn't since it tests before to make sure.
What you need to understand here is that SuperClass myObject = list.get(0) is not the object itself, but a reference to access the object in memory. Think about it as a remote that allows you to control your object, in this case, it's not a fully featured remote, since it doesn't show you all your object can do, so you can switch to a better one (as in Subclass myObject = (Subclass) list.get(0)) to be able to access all features.
I'd surely recommend the Head First Java book as it covers this stuff in great detail (and I stole this remote example from there).
All of the objects retain their own class identity, but the code that uses the ArrayList isn't directly aware of it. As far as it's concerned, the ArrayList only holds references to SuperClass-type objects, and it can only call SuperClass's methods on objects it retrieves from it.
The calling code can use instanceof or similar techniques to find out if a particular object in a collection is of a subtype, but this is usually bad practice, since it usually indicates mixing of the different levels of abstraction. The one case where this is generally considered reasonable is if the subclass has some optional high-performance characteristic that the caller can take advantage of (and that measurement has determined is worth complicating the code for); one example might be that while List's get() method is has no performance guarantees, some implementations, like ArrayList, also implement RandomAccess, which indicates that there's no performance penalty to using get() in any order.
When you have some ArrayList and you fill it with things that extend SuperClass you have to check instanceof and cast to get to the methods specific to those subclasses.
Example:
ArrayList<Animal> animals = new ArrayList<Animal>;
animals.add(new Duck());
animals.add(new Cow());
animals.add(new Horse());
for (Animal animal : animals)
if (animal instanceof Horse) {
Horse horse = (Horse)animal;
horse.gallop();
}
This is an Android app, but presumably it happens the same in Java. I have a type LevelFactory from which I derive Level1Factory, Level2Factory, etc. I want to have an array of these classes so I can instantiate a level given the array index.
I can just have a Class[] and put them in that and then just cast them to LevelFactory when I need to use them, but I was wondering what the proper thing to do is.
This is obviously an error "Incompatible types":
new Class<LevelFactory>[] {Level1Factory.class,Level2Factory.class};
However, I was surprised to see that this is also an error "Generic array creation":
new Class<? extends LevelFactory>[] {Level1Factory.class,Level2Factory.class};
The following works, but it gives the "Unchecked assignment" warning when assigned to a variable:
new Class[] {Level1Factory.class,Level2Factory.class};
The last is the only option I can get to work. I just ignore the warning, but I would like to do it using generics if that's actually possible.
I would recommend you to read Item 25 "Prefer lists to arrays" of book "Effective Java". There Joshua Bloch writes:
Why is it illegal to create a generic array? Because it isn’t typesafe. If it were
legal, casts generated by the compiler in an otherwise correct program could fail at
runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system.
UPD: Maybe with concrete example it would be more understandable.
First of all arrays are covariant which means that SuperClass[] can be cast to SubClass[] and vice versa. It also means that it's legal to cast AnyConcreteClass[] to, say, Object[].
So Let's assume that it's possible to have Set<Cat>[] (but it is NOT). If somebody cast this array to Object[] and then add there a set of Dog instances, Java couldn't guarantee anymore that our array contains only sets of Cat instances. Breaking type safety it breaks essence of generics. That is why it's illegal have generic array.
Set<Cat>[] cats = new Set<Cat>[]; // illegal
Object[] objects = cats;
objects[1] = new Set<Dog>();
cats[1].add(new Cat()); // Oops! TypeCastException
Honestly saying this example also was taken from Effective Java :)
Two questions:
Do you really need an Array? Arrays don't work great with generics. So an ArrayList<LevelFactory> might be the better solution
Do you really need the downcast to the special type (Level1Factory, Level2Factory)? If they have a common super method which is defined in LevelFactory (lets say Level getLevel()) you should not need to downcast them. Just call getLevel() and you get the correct Level instance from your factory.
Another note because this seems to be a common pitfall:
new Class<? extends LevelFactory>
This is not a valid statement (it does not matter if its an array or not). <? extends T> is only valid for the type on the left side. It defines that the generic type of the created Object can be T or derived from T. For Collections this does not mean that they can store objects of T or derived from T (which can a Collections of T anyway).
List<LevelFactory> list = new ArrayList<LevelFactory>() This means you can add objects of LevelFactory, Level1Factory and Level2Factory to list. When you want to receive objects from list they are of type LevelFactory.
List<? extends LevelFactory> list = new ArrayList<LevelFactory>() Means you can receive objects of LevelFactory from list. BUT you cannot add any object to list in a typesafe way because you don't know the exact generic type of list. That because you can also assign new ArrayList<Level1Factory>() to list. Which means that you can't even add LevelFactory objects to list because they don't implement Level1Factory.
In general <? extends Something> on collections is not what you want in most cases.
You can't create array this way new SomeClass<Type>[10] but only this way new SomeClass[10]. Consider using ArrayList<SomeClass<Type>> instead.
How does Java do this? If there are not multiple Classes being created, then how does it support multiple Typed instantiations of the Generic class?
Until now I used to believe that it is like C++, but now i am totally confused.
Can't figure out how Java pulls this off?
-Ajay
This is due to type erasure. Java's generics are primarily a compile-time feature. All generic types are, at runtime, Objects replaced with their lower bound.
Thanks to Michael for the correction:
Generics are not strictly a compile-time feature. If a class, method or field has a generic type with a concrete type parameter specified, this information will be present at runtime and is available via reflection.
To elaborate:
When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to. In short:
You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and methods where it is used and parameterized. Its concrete parameterizations in other words.
Source
Since only reference types can be used as generic type arguments in Java, and all pointers are the same size, the same byte code can be used.
As for type safety, generics in Java a compile/link-time only. That is, during compilation generic types are replaced by their erasure. The erasure of a type variable T is its lower bound (or Object, if it doesn't have one). For instance,
class Complex<N extends Number> {
N real;
N imag;
}
becomes
class Complex {
Number real;
Number imag;
}
as far as byte code is concerned.
Needless to say that is not pretty and causes numerous limitations. The most obvious one is that
new N();
does not compile, because the runtime does not know the type N stands for and hence can't instiate the type. Similarly,
(N) n
will compile, but unlike an ordinary cast in Java, will not be checked at runtime. An incorrect cast can therefore cause a variable to hold an object of the wrong type. This is called heap pollution. To ensure (a weaker form of) type safety, the compiler will introduce casts into calling code. For instance,
boolean right(Complex<Integer> c) {
return c.real > 0;
}
will become
boolean right(Complex c) {
return ((Integer) c.real) > 0;
}
To sum things up, the generics implementation in Java is not pretty, especially compared to the .NET one. The things we have to live with for the sake of backwards compatibility ...
good question. The genetic information is not kept during runtime. E.g if you have this code
List<Apple> apples = new ArrayList<Apple>(); // this is a list of apples
But in runtime it becomes :
List apples = new ArrayList(); // this is how it looks in runtime