Cannot make a static reference to non-static method issue - java

I have overriden the method toString() in class Person, but i cant use it in my main method - "Cannot make a static reference to non-static method toString() from the type Object"
class Person {
private String name;
private int id;
public Person(String name,int id) {
this.name = name;
this.id = id;
}
#Override
public String toString() {
String result = "Name: "+this.name+" ID: "+this.id;
return result;
}
}
public class Testing {
public static void main(String[] args) {
Person person = new Person("Ivan",1212);
System.out.println(toString()); // Cannot make a static reference to non-static method
}
}
How can i fix this ?

Use:
System.out.println(person.toString());
toString method is a non-static method, meaning it is related to a specific instance.
When you want to call it, you need to call it on a specific Person instance.

You're trying to call a non-static method from a static context (in this case, your main method). To call the Person object's toString method, you'll need to do person.toString().
Sometimes thinking of our code as English helps us make sense of it. The English for this statement is "Convert the person to a string.". Let's turn this into code.
Person maps to the person object we've created. "to a string" maps to the toString() method. Objects and verbs (methods) are separated by periods in Java. The complete code for the English above is person.toString().

You can't call the method like that, you should use the referece "person" !
System.out.println(person.toString());

toString(....) is a member method of the Person Class. That means you can invoke it via an object instance of the class. So, you need to invoke person.toString() instead of toString() in System.out.println(....);

Related

Calling a function placed in another function that is in another class

I couldn't grasp the idea why the codes below prints console Person twice. I thought it should have been Person and Student. When getInfo() inside printPerson() is called through "a" object, why is the one inside Person class being invoked and why is the one in the Student class not invoked? Thanks in advance.
class deneme{
public static void main(String[] args) {
Person b = new Person();
b.printPerson();
Student a = new Student();
a.printPerson();
}
}
class Student extends Person {
public String getInfo() {
return "Student";
}
}
class Person{
private String getInfo() {
return "Person";
}
public void printPerson() {
System.out.println(getInfo());
}
}
You have attempted to override a private method. That is not possible. See Override "private" method in java for details. Because Student is not able to see Person.getInfo Java assumes you are declaring a new method.
If you make getInfo public you will find that Student is printed instead.
This is a good argument for using the #Override annotation before any methods that you are intending to override a superclass's method. It isn't just documentation - it can avoid subtle errors by letting your IDE warn.
I think that is because Person.getInfo() is private and you cannot override private methods, so a.printPerson() will actually call its own getInfo(). Always annotate methods you want to override with #Override; the compiler will throw an error if there was no method found in the parent class to override.
If you want to make Person.getInfo() private to other classes but still want to override it, simply make it protected.

Why does the method reference I am passing to Arrays.sort need to be static?

I am new bie to Java 8. I am trying to create a sample for Reference to an instance method of an arbitrary object of a particular type.
I have a person class with one field Name and trying to sort Array of Person objects on firstName field of person class.
public class Person{
String firstName;
public Person(String firstName) {
super();
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public int compareByFirstName(Person p1, Person p2) {
return p1.getFirstName().compareTo(p2.getFirstName());
}
}
public class TestInstanceMethorRefArbObjSample {
public static void main(String[] args) {
TestInstanceMethorRefArbObjSample obj=new TestInstanceMethorRefArbObjSample();
obj.personSorting();
}
private void personSorting() {
Person[] personArr= {new Person("Jinesh"),new Person("Sejal"),new Person("Ashish")};
Arrays.sort(personArr,Person::compareByFirstName);
}
}
But I am facing compilation issue on below line.
Arrays.sort(personArr,Person::compareByFirstName);
1.The type Person does not define compareByFirstName(T, T) that is applicable
here TestInstanceMethorRefArbObjSample.java /InstaceMethodArbitaryObjectProject/src/com/methodreference/instancemethodrefarbitary/client line
11 Java Problem
2.The type Person does not define compareByFirstName(T, T) that is applicable
here TestInstanceMethorRefArbObjSample.java /InstaceMethodArbitaryObjectProject/src/com/methodreference/instancemethodrefarbitary/client line
11 Java Problem
I am just trying to pass the implementation of int compare(T o1, T o2); using compareByFirstname of Person class.
As soon as I am changing the method compareByFirstname of Person class to static everything is working fine.
Why I need to change the compareByFirstname to static method to make it work?
Some background
Arrays.sort expects a Comparator, which, when passing a method reference, must be a method that accepts two instances of the appropriate type.
There are two ways to create such a method:
Create a static method in any class that accepts two parameters of the appropriate type. This is essentially what you have done. Such a method does not need to be declared in the specific class, you could also have some other class that provides such helper methods.
Your compiler will make sure that the generated Comparator instance calls the referenced method with the 2 instances it wants to compare.
Create an instance method in the specific class for that type that accepts one parameter of the appropriate type.
Your compiler will make sure that the generated Comparator instance calls the referenced method on the 1st instance with the 2nd instance as parameter.
Your specific case
Since your method takes two parameters, it must be static, as it otherwise needs a third instance to run. Either declare it static, or remove one parameter and implement the comparison between this and the parameter.
You are using a method reference and since you have written it as Person::compareByFirstName it is referencing a static method. If you wanted to reference an instance method instead you would need to first create an instance of the object, then you would reference the method with the instance, like so:
Person p = new Person("");
p::compareByFirstName
However this would not be what you want to do in your case as the compare method is not instance-specific.
You could change your comparison method to make it specific to the instance by comparing the object instance with another object
public int compareByFirstName(Person p2) {
return this.getFirstName().compareTo(p2.getFirstName());
}
In which case you would be able to use the method reference Person::compareByFirstName as the comparison becomes arbitary.

Java Inheritance - Base class methods being overriding by derived class when using base variable for derived object

I've been preparing for the OCA Java SE 8 certification, and I've been doing a lot of studying, one of the hardest part for me, have been Inheritance, mainly because I started programming with PHP, so my programming haven't been so object oriented. Anyway, my issue is the following:
class MyOffice{
public static void main(String args[]){
Employee emp = new HRExecutive();
int x = emp.getInt();
System.out.println(x);
}
}
class Employee {
public String name;
String address;
protected String phoneNumber;
public float experience;
int y = 12;
/* COMMENTED CODE THAT GETS OVERRIDDEN WHEN UNCOMMENTED
public int getInt(){
System.out.println("Employee getInt");
return y;
}
*/
}
interface Interviewer{
public void conductInterview();
}
class HRExecutive extends Employee implements Interviewer{
public String[] specialization;
int elInt = 10;
public void conductInterview(){
System.out.println("HRExecutive - conducting interview");
}
public int getInt(){
System.out.println("HRExecutive getInt");
return elInt;
}
}
Using Employee variable to create a HRExecutive object, it doesn't allow me to reach any of HRExecutive members, trying to compile will fail due to not found symbol, which makes sense.
BUT when I remove the comments, and declare getInt() in base class Employee, it get's overridden by HRExecutive's method. It prints "HRExecutive getInt" and "10".
If previously Employee didn't have access to HRExecutive members, why after declaring the same method in class it is getting overridden? This is what I would like to understand.
At compile time you only know the static type of the instance which is Employee in this case. When Employee does not have a getInt() method you cannot call it.
But if getInt() is declared for an Employee it can be called and at runtime the method corresponding to the dynamic type of the instance, which is HRExecutive will get called.
"If previously Employee didn't have access to HRExecutive members, why after declaring the same method in class it is getting overridden?"
The reason for this is dynamic binding. Even though The method 'getInt()'is called by an 'Employee' variable, it is invoked on a 'HRExecutive' object. Hence, during run time, the method call will be resolved the subclass method i.e. method in 'HRExecutive' . If there is no overriding in 'HRExecutive', superclass method will get called.

Call of method in inheritance

I had a problems about the type of the objects and which method they can call.
I was just testing the usage of inheritance and I define two classes: superclass Person and subclass Student. The code is as below.
public class Person{
private String name;
private int birthday;
public Person(){
}
public Person(String name, int birthday){
this.name=name;
this.birthday=birthday;
}
public void setName(String name){
this.name=name;
}
public void setBirth(int birthday){
this.birthday=birthday;
}
public String getName(){
return name;
}
public int getBirth(){
return birthday;
}
public String toString(){
return "Name: "+name+"\n"+"Birthday: "+birthday;
}
public void print(Person a){
System.out.println(toString());
}
}
Student class:
public class Student extends Person{
private String major;
public Student(){}
public Student(String major,String name,int birthday){
super(name,birthday);
this.major = major;
}
public void setMajor(String major){
this.major=major;
}
public String getMajor(){
return major;
}
public String toString(){
return "Name: "+getName()+" BOD: "+getBirth()+" Major: "+getMajor();
}
public void print(){
System.out.println(toString());
}
}
Tester.
public class persontest{
public static void main(String[] args){
//Part 1
Person p2 = new Person("p2 Ryan", 19920604);
p2.print(p2);
//Test 1 p2-->Student
p2=new Student();// what does it mean??
p2.print(p2); //which 'toString' should be called??
//1.If p2 is now a Student Why can't invoke Student's print()? (Uncomment 'p2.print()')
// p2.print();
//2. If p2 isn't a Studnet, why is it able to call Student's toString()? (Uncomment toString in Student)
}
}
I declare 'toString()' method and 'print()' method in both Person and Student class.
As the method 'print()' has parameter in Person class while that doesn't have parameter in Student class, I think this method is overloaded instead of being overridden.
'toString' method has been overridden in Student class.
In Part 1, I create an object p2 with initialisation of name and birthday and the output is satisfied (Name: p2 Ryan Birthday: 19920604).
)
Then I tried 'p2=new Student()', so what does this mean? Changing the type of p2 from Person to Student?
Then I did 'p2.print(p2)' which I think called the method ' print()' in Person class, but which 'toString' has been called and used as the parameter? The printout is (Name: null BOD: 0 Major: null), which I thought indicated that the Student's 'toString' method has been called and processed. And it might prove that p2 now is a type of Person?
However, when I tried to get p2 call 'print()' in Student method, error came up as 'The method print(Person) in the type Person is not applicable for the arguments ()', which seems to say that p2 is still a Person so that it cannot call the method 'print()' defined in Student class.
So I got confused that what type is p2?
Weak and strong types: A representation:
Each variable that is not a primitive can be seen to have a weak type and a strong type. The weak type is used for overload resolution and for the compiler to see what interface an object has. But the strong type is used when actually calling a method on an object. Note: the strong type is always the same as, or a direct or indirect subtype of the weak type. Let's have a look:
A obj = new A();
Both the weak and strong type is A.
A obj = new B();
The weak type is A but the strong type is B.
The compiler uses the weak type to check which interface (the collection of methods) an object has. So we can only call methods from A on obj and not from B. So if the classes look like this:
class A { }
class B extends A {
public void bMehtod(){
...
}
}
We cannot call bMethod on obj, because bMethod is not part of A's interface.
For the sake of overriding, The strong type is used when actually calling a method. It's like the JVM starts at the strong type and moves up the inheritance chain until it finds an occurrence of the method that was called. So if our classes look like this:
class A {
public String toString() {
return "A";
}
}
class B extends A {
public String toString() {
return "B";
}
}
And we create an object and call toString:
A obj = new B();
System.out.println(obj); // this will call 'obj.toString()'
The JVM will start at the strong type (B) and look for a toString method. If it can't find any, it will move up the inheritance chain. But, B overrides toString so B's toString will get called. This becomes more apparent when a third class is added:
class C extends B { }
If we now create an object and call toString:
A obj = new C();
System.out.println(obj);
The JVM will start at C looking for a toString method, it wont find any and move up, to B, where it finds a toString method. So B's toString method will get called.
How does this relate to your problem:
Just like other variables, this has a weak and strong type. The weak type is the class in which the this keyword is written. The strong type is the actual type with which an object was created.
In your print method:
public void print(Person a){
System.out.println(toString());
}
The toString() is implicitly translated to this.toString(). The weak type of this is Person, so it's okay to call toString on it, it's a part of Person's interface. But the strong type is what you actually used to create the object:
p2 = new Student();
The strong type of this is Student, so the JVM will start at Student when looking for a toString method, and it finds it in Student. So Student's toString method is called.
Like I said this is just a representation, the actual way it is implemented could vary per JVM. But it will still behave the same.
Also, see Live Demo
public class persontest{
public static void main(String[] args){
//Part 1
Person p2 = new Person("p2 Ryan", 19920604);
p2.print(p2);
// Here super class variable p2 is holding super class object. Hence print() method of Person class will be called which is indirectly calling toString() of Person class only
//Test 1 p2-->Student
p2=new Student();// It means Super class variable P2 is now holding subclass Student object.
//It means now whenever we try to call a method, it will first check whether it is available in subclass or not
// if available it will be called, if not available, it will check in superclass for same method
p2.print(p2); //which 'toString' should be called??
// Now as you called print(p2)-> JVM will check whether a print method with one parameter is available in Student class or not?
// As per your code it is not available, then it will check if Print method with one parameter is available in super class. It is available
// Hence super class print method will be called. As there it is calling toString() which is available in that class only
//hence Person class toString will be called
//1.If p2 is now a Student Why can't invoke Student's print()? (Uncomment 'p2.print()')
// p2.print();
//2. If p2 isn't a Studnet, why is it able to call Student's toString()? (Uncomment toString in Student)
}
}
With Person p2 = new Student() you have declared a new variable of type Person but assigned a student object to it.
The variable type is still person so you can not directly call methods from student on it.
To do so you have to cast it to student first
((student) p2).print()
This will invoke the print() method from student class.
However if you are overwriting a method you always invoke the method from your object because the complier checks to run time of which type your object is and calls the method on this object. This is called dynamic binding.
The only way to access the overwritten method from person in a student object is to invoke the method with super so:
super.toString();
But that can only be done inside the student class.

Can void be used in toString method

I am creating a program but i want to print the string from toString method directly with using System.our.println(ClassName.toString()),
Instead i want just to write the ClassName.toString(); and it print the output.
No, because if you want to call toString method like ClassName.toString(), that means you want to create a static toString() method in your ClassName class, means you are hiding toString instance method of Object class with static method of your class, but Java rule says you cannot hide instance methods with static method.
Java Specification reference: jls 8.4.8.2. Hiding (by Class Methods)
It is a compile-time error if a static method hides an instance method.
toString() method is a method available in Object class.
any class in java if its not extending any parent class then it will have internally Object class as parent.
and toString() method is non final in Object class
so it means we can override the toString() method in any of the subclass.
and return type of overridden methods should be same if its built in type and it should be same or parent if its custom object.
so in our case of toString() its return type is String so nobody can replace String for return type.
hence changing it will give compile time error.
so to achieve your scenario you can do as below in the worst case
#Override
public String toString() {
System.out.println("your string");
return super.toString();
}
and call this method using object of this class, if class name is A
then
A a = new A();
a.toString();
will automatically print the content on console using its body.
I feel like the other answers have covered “don’t do that”, but this is my “try this instead”. But if you are simply trying to accomplish a more terse way of printing the toString() output you could do something like this instead:
public class PrintMe {
private String data = "Just an example";
#Override
public String toString() {
return data;
}
public void print() {
System.out.println(toString());
}
public static void main(String[] args) {
PrintMe p = new PrintMe();
p.print();
}
}
Output: Just an example

Categories