Having trouble understanding the intricaies of upcasting/downcasting, and static binding and dynamic bidning in these cases. Please consider the following classes and interface example:
public class Marsupial { private String name;
Marsupial(String name) {
this.name = name;
}
void eats() {
System.out.println("Eats #1");
}
String getName(){ return name;
}
}
abstract class Herbivore extends Marsupial {
Herbivore(String name) {
super(name);
}
void eats() {
System.out.println("Eats #2");
}
abstract void chews(boolean b);
}
interface Australian {
public void greets(Koala k);
}
public class Koala extends Herbivore implements Australian {
Koala(String name) {
super(name);
}
public void greets(Koala k) {
System.out.println("G'day mate!");
System.out.println(getName() + " " + k.getName() );
}
void chews(boolean b) {
System.out.println("Yum yum!");
}
void chews(int i) { System.out.println("Delicious!");
}
void likes(Koala k) {
greets(k);
k.greets(this); }
}
Now when I make a driver class to use all of the classes I notice some odd things happening that I am not sure why.
For example,
public class Driver {
public static void main(String[] args) {
Marsupial m = new Marsupial("Kate");
Marsupial m2 = new Koala("Kim");
System.out.println(m.getClass() == m2.getClass());
}
}
This turns out to be false. They are not the same class. So what is happening here exactly. We have Marsupial on the left and something else on the right. So does what's on the right the only thing that matters when we are calling methods? When the compiler runs and looks at methods does is check the right side of the equals operator and say ok this is such and such class, therefore use the methods of the class defined on the right side when figuring out whose class to use.
Also,
if inside the main method I wrote:
Marsupial m = new Koala("jack");
m.eats();
This prints out Eats #2. Now is this because since Koala does not have a eats method is just goes back one level up the chain, so the next level up would be Herbivore and since that has an eats() method that is what gets called, is that the idea there?
Another example in the main method:
Herbivore h = new Koala("June");
((Marsupial)h).eats();
Here the thing that throws me off is that we can use abstract classes as a reference to actual objects, like here Herbivore is an abstract class therefore cannot be instaniated, but it can be assigned to a class that does instantiate an object.
But what confuses me most is that now we are in the Koala class and we call the eats() method but then we UPCAST the variable to Marsupial. So does that automatically put us in the Marsupial class and therefore anytime we call a method even if its in other classes the Marsupial class method is the one that gets called since we typecasted it to Marsupial, therefore its Eats #1.
Another area of confusion is if we do this in main:
Australian a = new Koala("Khloe");
a.chews(true);
It's werid seeing an interface be assigned to a subclass instantiation. It confuses me what would get called with a.chews(true). So since it's been defined as a Koala object then we are IN the Koala class and must use Koala methods if they exist, and if not there we go one level up to check that they have that method and so on and so fourth. But here the method is invalid. So does it only work if Australian had a prototype method in there and Koala defined it? then it would work? Is that the idea behind setting interfaces as objects of their subclasses? Even though Koala has that method since Australian does not, it will not work.
And if we have the code in main like:
Herbivore h = new Koala("Stacy");
h.chews(true);
this will print out "Yum yum" only because Herbivore had that prototyped undefined method and Koala defined it. But if Herbivore didn't have that prototype method is wouldn't work.
The last question I have is if this were run in main:
Herbivore h = new Koala("Kali");
h.chews(4);
This won't work because despite the fact that Koala has this method in there, it's not defined in Herbivore, so it's invalid.
Please help, any corretions or information you could provide would be very helpful.
Thank you
The answer to all is one: as far as
the JVM is concerned it doesn't
care one bit about the variable
type, but only the actual type (the
one used with the new keyword)
. Variable types are for the
compiler only to ensure type
safety as early in development
possible.
Related
I've got the following code example:
class p {
public void druckauftrag() {
// ...
drucke();
}
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp extends p {
public void drucke() {
System.out.println("Color-Printer");
}
}
Calling the following lines:
cp colorprinter = new cp();
cp.druckauftrag();
There is no problem understanding why "cp.druckauftrag();" results in console output "Color-Printer".
But when I call:
p drucker = (p)colorprinter;
drucker.druckauftrag();
I get the same output - why?
Does the typecast overwrite the object "drucker" 's method "drucke" with "drucke" from colorprinter?
Thanks in advance for every explanation.
colorprinter does not stop being an instance of cp when you use the cast operator on it, so its implementation of public void drucke() does not change
What you are expressing with your (p)colorprinter casting is the kind of contract (interface) you expect the object colorprinter to satisfy, which includes a public method with the signature public void drucke(), but not any specific implementation.
And, by the way, this casting is already performed implicitly when you declare drucker of the type p, so (p) is redundant in p drucker = (p)colorprinter;. p drucker = colorprinter; will suffice.
Here you can learn more about typecasting.
Keep in mind that it's best practice to extend from abstract classes or interfaces and only #Override (implement) abstract methods. A better design of your code would be:
abstract class BasePrinter {
public void druckauftrag() {
// ...
drucke();
}
public void drucke();
}
class p extends BasePrinter {
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp extends BasePrinter {
public void drucke() {
System.out.println("Color-Printer");
}
}
But of course constraints don't always allow for that kind of redesign. Passing the base requirements as parameters to the constructor (dependency injection) instead of extending a base class can also be a good alternative:
interface Druckable {
void drucke();
}
class Druckauftrager {
Druckable dk;
Druckauftrager(Drukable dk){
this.dk = dk;
}
public void druckauftrag() {
// ...
dk.drucke();
}
}
class p implements Druckable {
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp implements Druckable {
public void drucke() {
System.out.println("Color-Printer");
}
}
Now, if you want to express that a printer requires or can have multiple printing capabilities (like both color and b/w), you just write the class with as much extra Drukable properties and constructor parameters as you want, for example:
class BlackAndWhiteOrColorPrinter {
p blackAndWhitePrintService;
cp colorPrintService;
Druckable selectedPrintService;
BlackAndWhiteOrColorPrinter (p blackAndWhitePrintService, cp colorPrintService){
this.blackAndWhitePrintService = blackAndWhitePrintService;
this.colorPrintService = colorPrintService;
this.selectedPrintService = blackAndWhitePrintService;
}
public void druckauftrag() {
// ...
selectedPrintService.drucke();
}
}
This way, you can even write a class MultiPrinter with a MultiPrinter(List<Druckable> printServices) constructor and add any number of printing modes to its list of printing services: p, cp, and whatever other implementation of Druckable with its public void drucke() comes in the future. It is also extra practical if you want to introduce unit testing, so you can provide mockup objects that force the particular conditions you want to test, like druke() throwing a PaperJamException, for example.
For more information on how interfaces, overriding and inheritance work, see https://docs.oracle.com/javase/tutorial/java/IandI/usinginterface.html
BTW, acording to the latest revision of the official java code conventions guide and also by de facto standard, classes in Java should use CamelCase naming convention. You can also benefit greatly from using semanting naming on all your definitions, like BlackAndWhitePrinter blackAndWhitePrinter and ColorPrinter colorPrinter.
colorprinter is an instance of cp. Even when you upcast it to p, it's drucke() method will be still the one from cp.
The difference is that after you upcast colorprinter, you will not be able to invoke the methods that cp defines on its own.
When you create an object using new operator, memory is allocated in heap. Methods and fields are actually there depending upon the concrete actual class of the object.
Alter a sub class overrides and modifies a behavior from its super class, invoking the overridden method will always result in the modified behavior. Casting will only mean that the object of sub class is now represented by the super type as the object has a modified behavior for a method will always result in the modified behavior.
Suppose you have below classes
public class Fruit{
public void taste(){
System.out.println("depends upon the actual fruit");
}
}
public class Mango extends Fruit{
#Override
public void taste(){
System.out.println("sweet");
}
public void wayToExposeSuperMethod(){
super.taste();
}
}
In other words its like calling mango as a fruit but still mango remains mango.
For above code
Fruit fruit = new Mango();
fruit.taste(); // <-- this will output : sweet
((Mango)fruit).taste();// <-- this will output : sweet
fruit.wayToExposeSuperMethod(); // <-- this will not compile
((Mango)fruit).wayToExposeSuperMethod(); // <-- this will output : depends upon the actual fruit
I have two classes Test and Encap. I have a private variable a and access via setter and getter method. and i'm inheriting the class Test with Encap.
now i am able to change the value of a using setValue(int a). i want to restrict that option. i want it to make it as a read only value. please assist me in this.
class Test
{
private int a;
protected void setValue(int a)
{
this.a = a;
}
protected void getValue()
{
System.out.println("The assigned value of a is : "+this.a);
}
}
public class Encap extends Test {
public static void main(String [] args)
{
Test t = new Test();
t.setValue(4);
t.getValue();
Encap e = new Encap();
e.setValue(3);
e.getValue();
}
}
One option would be to delete the method setValue() from the class Test:
class Test
{
private int a;
protected void getValue()
{
System.out.println("The assigned value of a is : "+this.a);
}
}
Edit:
Why to do this? If Encap inherits from Test, it should be able to do the same actions as Test. Otherwise, what's the purpose of inheriting? If you still thinking that Test should be able to modify the value and Encap not, maybe your design is wrong. You could try something like this instead:
BaseClass
---------
+getValue
/ \
/ \
Test Encap
-------- ---------
+setValue
If you mean that you want a derived class to not expose public methods of the superclass, then your code probably 'smells'...
Remember that Inheritance models "Is A"
So in your example an Encap is a Test and you should be able to do anything to an Encap that you can do to a Test.
However, if you simply must inherit from a class where you don't want to expose a parent-class method, you can override the method and have its body do nothing. But for simple getter and setter accessor methods this is potentially very confusing for clients of your code.
If you can't reconcile things and calling setValue() on an Encap is never the right thing to do, i would recommend overriding the method, commenting it liberally and have it do nothing, or throw an exception to indicate to the client that they're doing something that doesn't make sense.
I have these two classes in different packages(named a and b)
package a;
import b.*;
public class Tree
{
int health = 100;
public void show()
{
System.out.println(this.health);
}
public static void main(String[] args)
{
Arb c = new Arb();
//System.out.println(c.health); is not visible
c.show();
}
}
package b;
import a.*;
public class Arb extends Tree
{
}
I know that field health can't be accesed by an instance of type Arb because is not visible,so it doesn't exist for an instance of Arb. All that it inherited is the public void show() method. Ok until now.
But from my tests, calling method show through object c outputs the answer 100,as the initial value for a Tree object.
My problem with understanding this is: The method calls this.health ,so as long as object c calls this method, this = c. But health shouldn't be visible...
Could someone explain what is actually happening there? Thank you!
Your statement "so it doesn't exist" is incorrect. It exists, it's just not visible.
An instance of Arb is also an instance of Tree, and code in Tree can see the field, while code in Arb cannot see it.
As you correctly said, the Arb class inherits the public show() method of the Tree class. When calling the method show() of the class Arb you are actually calling the show() method in Tree. Because this method can see the field health it can also print it's value.
I want to add an advice that runs for each object created from a set of classes (in my case, from a specific package) after initialization is complete. Consider this code:
public class Test {
public static void main(String[] args) {
new A();
new A(0);
new B();
new B(0);
new B(false);
}
}
class A {
public A() {
}
public A(int i) {
this();
}
}
class B extends A {
public B() {
}
public B(int i) {
this();
}
public B(boolean b) {
super(0);
}
}
for example, for new B(false), the advise should run after public B(boolean), but not after public A(int) of after public A(). Also note that I don't want to advise the constructor calls in main(); if objects are constructed from a 3rd party application that's not compiled with my aspect, the advise should still be there, i.e. the constructors themselves should be advised.
I thought this should work using some !cflowbelow() expression, but I had no luck. The closest I got is this:
after() : initialization(pkg.*.new(..))
&& !cflowbelow(withincode(pkg.*.new(..)))
&& !within(MyAspect) {
System.out.println(thisJoinPointStaticPart);
}
which gives this output:
initialization(test.A())
initialization(test.A(int))
initialization(test.A())
initialization(test.B())
initialization(test.A())
initialization(test.B(int))
initialization(test.A(int))
initialization(test.B(boolean))
i.e. this() executions are ignored correctly, but super() executions are not. Also, I fear this will ignore things like public B() {new A();} or similar, because new A(); is in a pkg.*.new(..) cflowbelow...
I can't imagine this isn't a use case that's useful over and over, but I didn't find any resources on it. An example where full initialization is necessary would be when logging newly created objects, but the toString() method uses the object's state. Advising anything else but the "subclass-most" constructor will yield in a log containing uninitialized values, and advising constructor calls will, as I said, not work with third party code (or code from a different package in my example).
For extra internet-cookies, how would I select the bottom-most (non-Object or other non-unadvised-superclass) constructor for injectting pre-initialization code?
Lets suppose I have the following two classes
public class alpha {
public alpha(){
//some logic
}
public void alphaMethod1(){
//some logic
}
}
public class beta extends alpha {
public beta(){
//some logic
}
public void alphaMethod1(){
//some logic
}
}
public class Test extends beta
{
public static void main(String[] args)
{
beta obj = new beta();
obj.alphaMethod1();// Here I want to call the method from class alpha.
}
}
If I initiate a new object of type beta, how can I execute the alphamethod1 logic found in class alpha rather than beta? Can I just use super().alphaMethod1() <- I wonder if this is possible.
Autotype in Eclipse IDE is giving me the option to select alphamethod1 either from class alpha or class beta.
You can do:
super.alphaMethod1();
Note, that super is a reference to the parent class, but super() is its constructor.
Simply use super.alphaMethod1();
See super keyword in java
You can't call alpha's alphaMethod1() by using beta's object But you have two solutions:
solution 1: call alpha's alphaMethod1() from beta's alphaMethod1()
class Beta extends Alpha
{
public void alphaMethod1()
{
super.alphaMethod1();
}
}
or from any other method of Beta like:
class Beta extends Alpha
{
public void foo()
{
super.alphaMethod1();
}
}
class Test extends Beta
{
public static void main(String[] args)
{
Beta beta = new Beta();
beta.foo();
}
}
solution 2: create alpha's object and call alpha's alphaMethod1()
class Test extends Beta
{
public static void main(String[] args)
{
Alpha alpha = new Alpha();
alpha.alphaMethod1();
}
}
It is possible to use super to call the method from mother class, but this would mean you probably have a design problem.
Maybe B.alphaMethod1() shouldn't override A's method and be called B.betaMethod1().
If it depends on the situation, you can put some code logic like :
public void alphaMethod1(){
if (something) {
super.alphaMethod1();
return;
}
// Rest of the code for other situations
}
Like this it will only call A's method when needed and will remain invisible for the class user.
Whenever you create child class object then that object has all the features of parent class.
Here Super() is the facilty for accession parent.
If you write super() at that time parents's default constructor is called.
same if you write super.
this keyword refers the current object same as super key word facilty for accessing parents.
Solution is at the end of this answer, but before you read it you should also read what is before it.
What you are trying to do would break security by allowing skipping possible validation mechanisms added in overridden methods.
For now lets imagine we can invoke version of method from superclass via syntax like
referenceVariable.super.methodName(arguments)
If we have classes like
class ItemBox{ //can sore all kind of Items
public void put(Item item){
//(1) code responsible for organizing items in box
}
//.. rest of code, like container for Items, etc.
}
class RedItemsBox extends ItemBox {//to store only RED items
#Override
public void put(Item item){ //store only RED items
if (item.getColor()==Color.RED){
//(2) code responsible for organizing items in box
}
}
}
As you see RedItemsBox should only store RED items.
Regardless which of the below we use
ItemBox box = new RedItemsBox();
RedItemsBox box = new RedItemsBox();
calling
box.put(new BlueItem());
will invoke put method from RedItemsBox (because of polymorphism). So it will correctly prevent BlueItem object from being placed in RedItemBox.
But what would happen if we could use syntax like box.super.put(new BlueItem())?
Here (assuming it would be legal) we would execute version of put method from ItemBox class.
BUT that version doesn't have step responsible for validating Item color. This means that we could put any Item into a RedItemBox.
Existence of such syntax would mean that validation steps added in subclasses could be ignored at any time, making them pointless.
There IS a case where executing code of "original" method would make sense.
And that palce is inside overriding method.
Notice that comments //(1) .. and //(2).. from put method of ItemBox and RedItemBox are quite similar. Actually they represent same action...
So it makes sense to reuse code from "original" method inside overriding method.
And that is possible via super.methodName(arguments) call (like from inside put of RedItemBox):
#Override
public void put(Item item){ //store only RED items
if (item.getColor()==Color.RED){
super.put(item); // <<<--- invoking code of `put` method
// from ItemBox (supertype)
}
}
beta obj = new beta();
Since you have created beta object , you cant refer directly to alphamethod1 of alpha object.
It can be modified as
class Beta extends Alpha
{
public void alphaMethod1()
{
super.alphaMethod1();
}
}