Hello guys I have question related to 'this' keyword in Java.
(1)
Lets say Computer extends from Machine and we have the current code:
public class Machine {
private String name = "Machine";
public void test()
{
System.out.println(this.name);
}
public void test2()
{
System.out.println(this);
}
}
public class Computer extends Machine {
public void test()
{
System.out.println(this);
}
}
public class main {
public static void main(String[] args) {
Machine c = new Computer();
c.test();
c.test2();
}
}
Its prints:
Computer#1db9742
Computer#1db9742
It means the 'this' in Computer refers to Computer and this is I understood but the 'this' in Machine also refers to Computer and this is what I didn't understand.
How this happened and why..???
(2)
So if Machine m = new Computer() this is true?
So to all that answered me, i can understand that this is related to the new or what we say what our Type pointing for...?
The keyword this refers to the current object, that is an instance of a class, not to a class itself. You have created a single object (with new Computer()), which is an instance of Computer. Since Computer is a subclass of Machine, it is also an instance of Machine, but the default toString() method will return a string containing the most precise type, in this case Computer.
Computer#1db9742 is just a name for your object. It is the same object, even if each method is defined in a different class.
"this" refers to the object, not to the class.
Computer extends Machine, so Computer inherits all the methods of Machine, making them their own.
When you instantiate Computer you're running all of it's methods.
You cannot access private variables from the class, you have to either create getter method or make the variable public, moreover this in System.out.println() calls toString() method, and if undefined, it prints something like that you have in results (type of object and location in memory).
Just create method in Machine class:
public String getName() {
return name;
}
And in main method make add following:
System.out.println(c.getName());
It's the instanciated type that counts. Not the reference.
Take this example:
class Animal{
void makeSound(){
System.out.println("wut ? Don't know what to do :(");
}
}
class Cat extends Animal{
void makeSound(){
System.out.println("Miaw !");
}
}
when you create for example:
Animal a = new Cat();
You're actually creating a cat. And still, a Cat is always an animal ? (Am I right ? :D)
a.makeSound() will result in printing Miaw !. But !
Animal a= new Animal();
a.makeSound();
will result in printing : wut ? Don't know what to do :( . What's the sound of an animal after all ? You see ?
If someone asks you to bring an animal, you can always bring a cat. Right ?
Well, this is the case with methods asking for an Animal parameter:
take this function:
void doSomething(Animal param){
// some code
}
you can call it using a Cat object as a parameter:
//...
doSomething(new Cat());
//...
Etc.. (you can push the analogy.. for a wider level)
Java VM takes the responsibility to make a type resolution at run time to decide which method to call. And that's some of the sweetness of OOP.
this is a pointer to the current object, and objects know what type they are.
this references the context that you are in. In your case, you are using it on the Machine and the Computer class.
To understand this, you need to first understand that the variable Machine m, is not the object itself, but it does reference to the object in the memory.
An then, you are calling from the same object, two different methods, one that is implemented on the objects class(Computer), and other that is implemented on its superclass(Machine).
Indifferently witch method is called, the object where you make the method call is the same, and the this keyword, will reference this same object, and then, the result of your test will be exactly the same object:
Computer#1db9742
Computer#1db9742
Related
What does it mean by "Casting affects the selection of overloaded methods at compile time but not overridden methods"?
I read the following passage on "Overridden methods and dynamic binding" (https://www.oreilly.com/library/view/learning-java-4th/9781449372477/ch06s01.html) and I couldn't understand the last paragraph
"In a previous section, we mentioned that overloaded methods are selected by the compiler at compile time. Overridden methods, on the other hand, are selected dynamically at runtime. Even if we create an instance of a subclass our code has never seen before (perhaps a new class loaded over the network), any overriding methods that it contains are located and used at runtime, replacing those that existed when we last compiled our code.
In contrast, if we created a new class that implements an additional, more specific, overloaded method, and replace the compiled class in our classpath with it, our code would continue to use the implementation it discovered originally. This situation would persist until we recompiled our code along with the new class. Another effect of this is that casting (i.e., explicitly telling the compiler to treat an object as one of its assignable types) affects the selection of overloaded methods at compile time but not overridden methods."
I couldnt understand the "Casting" line: "Another effect of this is that casting (i.e., explicitly telling the compiler to treat an object as one of its assignable types) affects the selection of overloaded methods at compile time but not overridden methods."
That line is referring to the fact that
overloaded versions of a method are chosen at compile time, based on the compile-time types of the arguments that you are passing; whereas
overridden methods are chosen at run time, based on the classes of the objects on which you call each method.
To understand this distinction, consider a situation where you have both overrides and overloads, like this.
public class Person {
}
---------------------------------------------------------
public class Postman extends Person {
}
---------------------------------------------------------
public class Dog {
public void barkAt(Person p) {
System.out.println("Woof woof");
}
public void barkAt(Postman p) {
System.out.println("Grrrr");
}
}
---------------------------------------------------------
public class Rottweiler extends Dog {
#Override
public void barkAt(Person p) {
System.out.println("I'm going to eat you.");
}
#Override
public void barkAt(Postman p) {
System.out.println("I'm going to rip you apart.");
}
}
In this situation, we call one of these barkAt methods, like this.
Dog cujo = new Rottweiler();
Person pat = new Postman();
cujo.barkAt(pat);
Now in this particular case, it's the compiler that chooses whether cujo.barkAt(pat); calls a method like public void barkAt(Person p) or public void barkAt(Postman p). These methods are overloads of one another.
To do this, the compiler looks at the type of the expression being passed to the method - that is, the variable pat. The variable pat is of type Person, so the compiler chooses the method public void barkAt(Person p).
What the compiler doesn't do is choose whether it's the method from the Rottweiler class or the Dog class that gets called. That happens at run time, based on the class of the object on which the method gets called, NOT on the type of the variable that you call the method on.
So in this case, what matters is the class of the object called cujo. And in this example, cujo is a Rottweiler, so we get the overridden version of the method - the one defined in the Rottweiler class.
This example will print out I'm going to eat you.
To summarise:
The overload is chosen at compile time based on the parameter type.
The override is chosen at run time based on the object class.
Now, it's possible to use casting to change the compiler's choice of overload. It's not possible to use casting to change the run time choice of override. So, we could write
cujo.barkAt((Postman) pat);
This time, the parameter passed to the method is an expression of type Postman. The compiler chooses an overload accordingly, and this will print I'm going to rip you apart..
Casting affects the selection of overloaded methods at compile time but not overridden methods
Overloaded methods are visible at compile time. But overridden methods becomes visible at runtime.
Thumb Rule:
Java calls the overridden methods based on contents of reference variable and not type of reference variables.
Below example is self explainatory. Hope it helps.
class Animal {
public void speak() {
System.out.print("Animal sounds/roars.");
}
}
class Human extends Animal {
#Override // Method is overridden
public void speak() {
System.out.print("Humans talking english.");
}
public void speak(String words) { // Method is overloaded.
System.out.print("We have brain. We are intelligent."+words);
}
}
class Earth {
public static void main(String a[]) {
Animal a = new Animal();
a.speak(); // Prints Animal sounds/roars.
Human h = new Human();
h.speak(); // Prints "Humans talking english."
Animal a = h; // Cast to superclass reference variable. However, underlying object is of Human.
a.speak(); // Prints "Humans talking english." because speak() is known by Animal at compile time. During runtime,
// the object contains the human object and hence java calls human overridden method.
a.speak("I want to be human."); // Compile time error as speak(..) is not known by Animal at compile time.
}
}
I am currently reading Herbert Schildt "Java the Complete Reference" and there he has used a term "Dynamic method resolution" and has provided a little explanation, but i am not getting the full import of it so asking for help in this forum.
while discussing 'interfaces', what he is saying is, dynamic method resolution helps in resolution of method name at run-time and it is achieved by declaring a interface variable and using it to refer to a class object. i.e
interface i = new object();
now what is so unique about it? you can use a class variable also to refer to the same object like:
class c = new object();
so, what is the use of interface here? and why introduce this new term "dynamic method resolution"??
Second he makes a point by saying: " when we use an interface variable to refer to instance of any class, and when you call a method through these interface variables, the method to be executed is looked up dynamically at run time allowing classes to be created later than the code which calls method on them. The calling code can dispatch through an interface without having to know anything about the callee".
Now, Anything dealing with objects has to be in run-time as objects are created at runtime, Now, I dont understand what he meant by "allowing classes to be created...on them".
Any help will be appreciated.
Here is a little example:
public interface Animal {
public String sound();
}
public class Cat implements Animal {
public String sound() { return "meow"; }
}
public class Dog implements Animal {
public String sound() { return "woof"; }
}
public class Test {
public static void main(String[] args) {
Animal a;
if (args.length > 0)
a = new Cat();
else {
a = new Dog();
}
System.out.println(a.sound()); // prints "MEOW" or "WOOF"
}
}
What is so unique about it? You can use a class variable also to refer to the same object
Yes. But you cannot use a single class variable to refer to an instance that can be an instance of any class that implements the interface.
In Test class, if I declared a to have type Dog or Cat there would be no way to get the code to compile. Without the ability to declare Animal a, I would need to have two distinct variables, and two separate print statements.
This is what dynamic method resolution (aka polymorphism) gives you.
To understand his second point:
public class Test2 {
public static void main(String[] args) {
Animal a = PetShop.buyPet(args);
System.out.println(a.sound()); // prints "MEOW" or "WOOF"
}
}
The Test2 class will work with my Cat and Dog class from above. It will also continue to work without recompilation if in 3 years time I implement a Goldfish class and modify my PetShop class to stock aquatic pets. And indeed, it is even possible to implement the PetShop class so that it doesn't need to be changed or recompiled to support other kinds of pets.
Now, these examples are clearly not practical. However, the Java features that they illustrate are useful in real Java applications. Indeed, a program as simple as a classic "hello world" program relies on dynamic method lookup.
dynamic method resolution means Single method which can be applied to solve multiple problems. Ex: Consider Shape is an interface and has method name draw.
you have Rectangle and Circle classes implements Shape Interface. So when you create instance of Rectangle object and call the draw method will draw the Rectangle shape.. In other case you can instantiate Circle instance and call draw method to draw Circle...
In interface you may assign child object in the parent container.
Ex: Shape p = new Rectangle();
in this case it will create the instance of Rectangle and assign it into Shape p..
but from the Shape p object you can call only the draw method... you can not call other methods in the Rectangle Object since its assigned to parent interface and parent has only draw method.
I have the following classes :
public abstract class Animal
{
private String species;
public Animal(String ll)
{
species = ll;
}
public abstract void speak();
public String toString()
{
return "Species: " + species;
}
}
The 2nd class:
public class Raven extends Animal
{
String name;
public Raven(String emri)
{
super("Raven");
name = emri;
}
public void speak()
{
System.out.println("krra krra");
}
public String toString()
{
return super.toString() + "\nName : "+ name ;
}
}
and the test class :
public class TestAnimals
{
public static void main(String args[])
{
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
System.out.println(a.toString());
}
}
When I execute the test class, I get :
Species: Raven
Name: Ziosh
What I don't understand is why does Java use the "new" toString() method, even after we "upcast" the Raven object to Animal ?
Thanks.
Because that's what polymorphism is all about: you can call a method of an object without knowing the actual concrete type of the object, and the appropriate method, defined in this concrete type, will be called.
This works exactly like real objects: if I give you a car, even if you don't know it's actually a hybrid car, the car will behave like a hybrid car when you drive it.
In your example, a and blabla are two references to the same object, which is a Raven instance. So this object *speak*s and *toString*s like a Raven.
When you call a method in java, even if it's cast to the super type, it always looks for the most overridden method to call.
From http://docs.oracle.com/javase/tutorial/java/IandI/override.html
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
Here, a and blabla reference the exact same object, as you can confirm with:
System.out.println(a == blabla);
// prints "true"
As such, a is really a Raven, so naturally it will talk like a Raven, even if you label it an Animal.
Consider another explanation in human terms. Letting the implementation to be executed on an object of a subclass could be actually very dangerous. Imagine a Bicycle class, and its more specialized BicycleWithLittleWheels. The thing about the latter, the little wheels are quite fragile, and if you try to ride it too fast, they could break. If you let somebody ride that bicycle as if was a regular bicycle, completely obvious of the little wheels, he may break it. By similar logic, you probably shouldn't use a high-precision dental drill the same way as a sledgehammer.
This is why, intuitively, you shouldn't let a specialized object be treated as its more general form. Sure, in some cases, it may make sense to use a specialized object as if it was something more general, but not always. How could the compiler distinguish the safe cases from the unsafe cases? That would be too difficult. So to stay on the safe side, the language won't let you do this.
Java always uses the method of the instance as describe in this post:
java override method invocation
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.
Let's say we have a class like this one:
class XCopy {
public static void main(String[] args) {
int orig = 42;
XCopy x = new XCopy();
int y = x.go(orig);
System.out.println(orig + " " + " y);
}
}
I know the go method is missing but never mind. Should this work? It appears so, but I just can't picture in my head how that self-reference inside the class works; does it have any side effects? Why does this work? Isn't that some sort of infinite recursive loop?
Anyway, I just can't figure out exactly how this works; thanks in advance.
I gather you are looking at this and thinking it is a chicken and the egg type issue, but it's not at all.
If this is your first OO language you are probably confused about Java's terminology. Java has something called "static methods". You're main(String[]) method is a static method. These static methods are really just plain old functions. Object Oriented methods on the other hand are called "instance methods" or just "methods". People are often sloppy about the terminology.
In Java, a function (i.e. static method) must be defined in the same place as a class and uses that classes' name identify it. But, it is still just a plain old function. Sometimes a class just has nothing but a bunch of loosely related functions/static methods. Like the Math class has a bunch of functions about math. Sometime a more OO class like string will have some static methods/functions thrown in with the OO methods.
In your program your main function has nothing to do with your class. But it's still perfectly fine to put it there for a small example.
When Java starts in ALWAYS starts in a main function somewhere (you can tell it what class the main function is in).
So when your program runs the JVM selects your main function as a valid main function. It runs the function. Its just a function it doesn't need any objects. Calling main does not create any objects.
Now, when your are in main(String[]) you happen to create an Object here:
XCopy x = new XCopy();
Now you have a new object of type XCopy pointed to by the reference (object pointer) x in the local scope of the main function. If XCopy had a constructor it would have been called.
So if you want to picture it in your head let me write it in a fictitious language for you that has a clear more visual syntax!
here it is:
Namespace XCopy
{
function void main(String[])
{
int orig = 42;
XCopy x = new XCopy();
int y = x.go(orig);
System.out.println(orig + " " + " y);
}
}
Class XCopy
{
method int go(int i)
{
....
return whatever;
}
}
In this same program in this other languages' syntax you can see that you have one function, one class with one method, and you have one instance of that class.
Hope that helps!!
By calling
XCopy x = new XCopy();
you are actually calling XCopy's empty constructor, not main method again.
So, the calls look like:
JVM calls XCopy.main();
main method creates new instance of XCopy by calling XCopy's empty constructor
XCopy constructor ends
main method ends -> program ends
Why would it recurse? main() isn't called anywhere within itself, so it wouldn't recurse. A class is in scope of its own members, so you can create instances of it.
Take for instance a makeCopy() method; it would need to create an instance of another object of its own type.
Don't think of methods as being "inside" a class/object and the action of calling a method from within itself as anything awkward; a method is just a function with an implicit this parameter.
The main method is static, meaning that its code can be accessed independently of the fact that there is an instance of Xcopy. Hence, there is no conflict or recursive loop. It has its own memory space which is different than the memory space allocated for each class instance.
main() is static, therefore you can consider it part of the class, but not of an instance. It gets called by OS+JVM and creates an instance of a class. That class happens to be the class where main() is defined, but that really doesn't matter.
Imagine a different class:
public class Person {
private String name;
private Person favorite;
public Person(String name) { setName(name); }
public void setFavorite(Person favorite) {this.favorite = favorite;}
public Person getFavorite() { return favorite; }
public void setName(String name) {this.name = name;}
public String getName() { return name; }
public static void main(String args[]) {
Person a = new Person("Alex");
Person b = new Person("Becky");
Person c = new Person("Chris");
Person d = new Person("David");
a.setFavorite(b);
b.setFavorite(c);
c.setFavorite(c);
}
}
So, Alex's favorite person is Becky. Becky's favorite person is Chris. But Chris is a narcissist; his favorite person is himself. David doesn't have a favorite person. Sadly, nobody thinks David is their favorite person.
When you apply the concept of self-references to something with real-world semantics, doesn't it make sense that such a structure is possible? Note, setting a self-reference doesn't create a copy. There is still only one Chris in this program.
As long as you don't make the move of saying, "I'm going to ask each person who their favorite person is. Then I'm going to ask that person who their favorite person is. I'm not going to stop until I find David. Because then, you do have a chance at looping forever.