I have a class called A (the parent) and class B (subclass of A)
My question is what is the difference between the next lines :
B b1 = new B();
A b2 = new B();
I know that variables and methods in class B cannot be accessed in case of object b2
But how it works in memory ? what is the point of this? when to use each of them ?
One reason to use the superclass as the variable type:
Suppose you have an Animal class, and several subclasses like Elephant, Tiger, Giraffe, Hippo, etc.
Now you have another class called Zoo, which contains an Array called animals. Then you could have:
animals[0] = new Tiger();
anumals[1] = new Elephant();
But it is better to have animals declared as an ArrayList that can grow or shrink:
animals.add( new Tiger() );
animals.add( new Elephant() );
animals.add( new Hippo() );
If a subclass has a method that is not an overload of a parent method, you can still access the subclass methods via the superclass variable by casting it:
Animal a = animals.get(index);
if ( a instanceof Tiger ) {
((Tiger)a).tigerMethod( ... );
}
Not that this type of thing might not be the best design, but it illustrates the point.
Object can have multiple Interfaces, let's say class B inherits from class A:
Class A can have 5 public methods,
Class B have additionaly 5 own public methods,
so in class B you see all 10 methods, whereas using class A you see only 5.
This is important, because in this way you can control which part (of the interface) of the class you give to other's (other programmers to use).
For egzample:
If you return from your public method a List<>, like:
public List<SomeClass> giveMeSomeList() {
// both return statements are perfectly valid as return type is List<>
return new LinkedList<SomeClass>();
// return new ArrayList<SomeClass>();
}
then you are allowed to use any implementation of the List<> you have eg. You can chnage the implementation, that you construct and return an ArrayList<> or LinkedList<> from your method, but since the declared return type is List<> it makes no harm, no one will rely upon that you return concrete implementation (at least your'e not responsible for that), just that it will be a kind of List<>. But if you return from your public method very concrete implementation of a class, then your give others invitation to use and rely upon this concrete implementation, which in turn block the methos from the ability to chanage the underlying implementation without doing harm to other code.
So in this way (using apropriate types) you can make some restrictions on other programmers as to which methods they are allowed to use (the interface), and give you some freedom to change the implementation in the future - like in the exmple with lists.
When you use an interface in an method arguments type, you make the method more general, as it can be used with any subtype of the interface (or type).
Sometimes you just need very concrete implementation as an argument to your method, because without that you cannot do the needed operation, so you will rely on very concrete type to be supplied to your method, and declare that type in the arguments of the method.
Related
I have had a burning question for a long time now, relating to the Java syntax and why it allows this:
Object object1 = new Integer();
Why can we declare child classes using Object as a reference?
Also, let's take a look at this piece of code:
public class Parent{}
public class Child extends Parent{}
public static void main(String[] args){
Parent var1 = new Child();
Object var2 = new Child();
Object var3 = new Parent();
}
All three cases will run, as I have tried this. The question is, does it matter whether I use Object to reference a new object/variable or the actual class name?
Also, how does the reference type selected affect the program and code? Does a certain reference type like "Object" take up less memory or make the program more efficient?
Thanks in advance
The question is, does it matter whether I use Object to reference a new object/variable or the actual class name?
Yes, it does. If you use the general interface/class name for your reference it will allow you to use dynamic dispatch, which means to decouple the client code from concrete implementations.
Let's say you have Cat and Dog classes which extend Animal class. Both classes overide makeNoise() method. Then you may write a code:
Animal animal = animalFactory.getAnimal();
animal.makeNoise();
Which is not dependent on a concrete implementation of animal: it may be Dog or Cat whatever you need. The advantage of this approach is that your code is less prone to changes. Less changes -> less bugs.
But it is important to mention, that you may only call the methods which are declared in the variable type. So, if your variable is Object type only Object methods are available to be called.
Because public class Parent{} is the exact same as
public class Parent extends java.lang.Object {
}
The compiler adds the "extends java.lang.Object" if you don't specify any super type.
For clarification:
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
As Oracle Doc
And in terms of OOP that's called type polymorphism which means by example:
If S is a subtype of T, the subtyping relation is often written S <: T, to mean that any term of type S can be safely used in a context where a term of type T is expected As this WIKI said.
Because of that any data types subtype can be assigned to Object instance
In terms of efficiency I don't think it makes any difference since you have that instance of the object type anyways.
The main advantages of using it might be to make Polymorphism. For instance
Object var1 = new GrandParent();
Object var2 = new Child();
Object var3 = new Parent();
List<Object> object_list = new ArrayList<>();
object_list.add(var1);
object_list.add(var2);
object_list.add(var3);
Of course this doesn't make much sense since you wouldn't have any advantage. But if you used an Interface you could call a method without specifing the type. Something like this:
IPerson var1 = new GrandParent();
IPerson var2 = new Child();
IPerson var3 = new Parent();
List<IPerson > object_list = new ArrayList<>();
object_list.add(var1);
object_list.add(var2);
object_list.add(var3);
for(IPerson person : object_list) {
person.laugh();
}
In this situation you could apply different algorithms inside each concrete class.
This is a Strategy Design Pattern.
Let us consider we have two classes A and B. B is a sub class for A because B extends A. If We create an instance of A Class and assign that in to a A type will contains all the properties of A. Similarly when I create an Instance of B and assign it to B type will get all the properties of B along with properties of A because it is inheriting from A. According to above lines instance of A contains properties a few as compared to properties contains to instance B. That means Instance of B is Bigger than Instance of A as casting should be explicit when narrowing implicit when widening. According to my theory Instance of B is bigger we are trying to store it in A type we need conversion.
A a1=new (A)B();
The above conversion is taking place implicitly. But my question is how it is implicit, Instance of B is bigger we are trying to convert that to small type which is A. How this is possible???
Answer me with examples thank you in advance.
You are thinking in terms of object size, but in Java, non primitive types are never contained, only referred to. Thus, your code is casting the result of new B(), which is of type "reference to B", to type " reference to A". Since all references are the same size, no data is lost in the cast.
So, I really don't understand your question. I just think you are confused about what happens to the class B members when a upcast to his super class is made. In that case, you ended up with a instance of A wich means that Object type is A and non of B stored data will remain.
In Java, with
B b = new B();
A a = b;
one defines references b and a. Under the hood, references are implemented with pointers, and thus, all references are the same size. Of course, an instance of a B might indeed require more memory than an instance of A (I take it, this is what you mean by "bigger").
By the way, in C++ this is not the case.
B b();
does define an object, not a reference, and therefore
A a = b;
in C++ is indeed not allowed.
Think about this:
class Animal{
public void eat(){}
}
class Monkey extends Animal{
public void climbTree(){}
}
I can now do this:
Animal someAnimal = new Monkey(); //This is ok. (Create a Monkey and identify is as an Animal)
someAnimal.eat(); //This is ok too. (All Animal objects can eat)
someAnimal.climbTree(); //Not ok. Java sees someAnimal as a general Animal, not a Monkey yet.
From the above example, someAnimal is a Monkey object which is stored within a variable of higher hierarchy (Animal).
The object itself is perceived as the a more general class (The Animal class) and I don't think an implicit casting is done here since all Monkeys are already Animals (but not the other way round).
Explicit casting can be done when you want to let the compiler knows that the object actually belongs to a more specific class. For example:
((Monkey)someAnimal).climbTree(); //This is ok. Inform Java someAnimal is actually a Monkey which knows how to climb.
Example :
Class Employee {
private String name;
private double Salary;
//getter & setter
//mutators to increase salary etc;
}
class Manager extends Employee {
private double bonus;
//inherits methods from superclass
// sub class specific methods
}
Employee e = new Manager(); //is fine as manager is also an Employee...
The prefixes super and sub come from the language of sets used in theoretical computer science and mathematics. The set of all employees contains the set of all managers, and thus is said to be a superset of the set of managers. Or, to put it another way, the set of all managers is a subset of the set of all employees.
~ From core java series
hope this helps...
The cast isn't actually implicit like you're saying. What is actually happening is this:
B b1 = new B();
A a1 = (A)b;
The (A) is an explicit cast, what's more important is to stop considering the size of things in the sense that the size of B is different from the size of A. This can be an implicit assignment because B IS-A A, so using A as an interface for B is completely safe, because we know that B has at least the same members as defined by A.
So the perfectly safe (and not erroneous) method of doing this is simple:
A a1 = new B();
Done!
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();
}
I have superclass A, which is extended by subclasses B1 and B2. Then, I have five subclasses (C1, C2, C3, C4, C5) that extend either B1 or B2.
I am trying to make an array containing one of each of these five subclasses.
These objects are all instantiated as instances of type A.
ClassA[] objects = new ClassA[5];
I attempt to reassign each of the objects to one of the subclasses:
objects[0] = new ClassC1;
objects[1] = new ClassC2; // etc...
At this point, any methods that existed in Class A work fine, but methods defined in B1/B2 or the other subclasses are not found:
objects[0].MethodFromC1(); // returns a "symbol not found" error
The instanceof keyword indicates that objects[0] is an instance of classes A, B1/B2, and C1.
What can I do to maintain my array of class objects (to loop through and perform operations), while getting my code to recognize the methods of the subclasses?
If you are doing a lot of instanceof and conditional logic based on class, you are completely missing out on the benefits of an object-oriented language. Just stick to C.
You should have some method do(), for example, that is abstract in ClassA but implemented in ClassB and ClassC. Then you iterate over the array and call do() on every object in there. The polymorphic call will result in the right do()'s being called.
Hope that helps.
Elements in the objects array don't know anything about ClassC1 since they're only guaranteed to be members of ClassA.
For instance, if you have a class hierarchy of Animal and subclass Cat and its subclass Lion, you're trying to call the Animal.maimSafarigoer() method. Animals in general don't know anything about safarigoers, only Lions know how to do that.
Use the instanceof operator to check if you're operating on a particular subtype.
(Sorry for the gruesome analogy. :-) )
You're trying to implement variants in Java. This subject has long been one of the things I hate the most about this language.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html
I have listed about 8 suboptimal ways to do variants there.
You can use the instanceof keyword in the if statement and cast the object to the desired type. For example,
for (ClassA obj : objects) {
// do something common...
if (obj instanceof ClassC1) {
ClassC1 c1Obj = (ClassC1) obj;
c1Obj.MethodFromC1();
}
}
I just saw a member function like this:
public Cat nextCat(GameState state);
But Cat is an interface like this:
public interface Cat {
void makeCat(GameState state);
}
So I am confused as to how to interpret this. I know what it means when something returns an object or a primitive. But what does it mean to return an interface? How to use this function's return value?
Think about this way: If Cat where a regular class, what exactly would you care about when you wanted to call some methods on it?
You'd care about the method definitions: their names, their argument types, their return values. You don't need to care about the actual implementation!
Since an interface provides all of that, you can call methods on it, just as you can on a regular class.
Of course, in order for the method to actually return some object, there needs to be some class that implements that interface somewhere. But what class that actually is or how it implements those methods doesn't really matter to the code that gets that object returned.
In other words, you can write code like this:
Cat cat = nextCat(GameState.STUFF);
cat.makeCat(GameState.OTHER_STUFF);
That code has no knowledge of the concrete type that implements the Cat interface, but it knows that the object can do everything that the Cat interface requires.
This function returns an object of a class which implements the Cat interface. The implementation details (for this concrete class) are up to you, as long as you implement all the methods of the Cat interface for it.
For example you could do this:
interface Cat {
String meeeeow();
}
public Cat nextCat(GameState state) {
return new Cat() {
public String meeeeow() {
return "meeeeeeeeeow!!!!";
}
};
}
in which case the method nextCat returns an implementation of the Cat interface by means of an 'anonymous-inner-class'. This shows that the code calling nextCat does not need to know which code implements the returned Cat interface. This is an example of one of the key strengths of Object-Oriented programming: because the calling code doesn't know the implementation, the impact of changing the implementation later on is small (as long as the interface remains the same).
This is one way of abstration, "Hiding Actual implementation", The Best Example is Map interface where if some API has return type as Map, then user actually don't need to care about the type of object implementation i.e. 'Hasmap for Hashtable', With the help of methods defined in Map interface, user can perform operation on the returned object because interface create a contract with the implementing classes that the "implemeting class must provide defination for declared method" otherwise declare that implementing class as abstract.
It is worth emphasizing once again that it is perfectly legal—and in fact very common—to have variables whose type is an interface, such as :
Measurable meas; //"Measurable" is an interface name.
Just remember that the object to which meas refers doesn’t have type Measurable. In
fact, no object has type Measurable. Instead, the type of the object is some class that
implements the Measurable interface. This might be an object of the BankAccount class or
Coin class, or some other class .
meas = new BankAccount(1000); // OK
meas = new Coin(0.1, "dime"); // OK
What can you do with an interface variable, given that you don’t know the class of
the object that it references?
You can invoke the methods of the interface:
double m = meas.getMeasure();
and also you should know that there can be type conversians between class and interface types.
It means, that the member function can return any implementation. This follows the "Program to an interface, not an implementation." design pattern.
Methods do not return interfaces or classes. They return a reference to an instance (=object) or null (or a primitive value, but let's stick with objects). This reference is usually either stored in a variable or used to call instance methods or access instance members.
The declared return type tells us the least specific type of the real instance, whose reference is returned by the method. The object behind that reference may be exactly that type or any subclass (or sub-subclass, ...).
A method can return nothing (void), or a primitive value int, double, ...), or a reference that is either null or refers to an instance. When a method returns a reference, it is
declared as returning a reference to some particular kind of object.
In your case, the reference this method returns will either be null or will refer to an object whose class implements Cat
When you don't need to know about implementation you can return interface to leave implementation to that method and caller can just use methods that interface provides.
Cat cat = nextCat(state);
cat.makeCat(state);
As per the object oriented definition, an interface is a group of related methods with empty bodies. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. Having said that, nextCat(GameState state) returns an Interface Cat which means that at runtime it could return any object which Implements Cat. Now, isn't that flexible?
Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect.
Returning interface allows a member function to return reference of any implemented class. It gives flexibility to program to an interface and also is helpful in implementation of factory and abstract factory design pattern.
It return an Object which implements the interface.
There are some examples for reference :
https://blog.csdn.net/hduxiejun/article/details/52853153