It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Effective:The choice of which overloading to invoke is made at compile time.
Example:
class parentsecond{
public int getdouble(int x){ return x*2;}
}
class second extends parentsecond{
public int getdouble(int x){ return x*3;}
}
class third{
public static void calloverload(parentsecond s){
System.out.println(s.getdouble(4));
}
public static void calloverload(second s){
System.out.println(s.getdouble(4));
}
public static void main(String[] args){
third t=new third();
parentsecond s=new second();
t.calloverload(s);
}
}
Answer is 12.
And the behaviour is the same for instance method overloaded method too.
So in either case ,the decision of which overloaded method is invoked is made at run-time rather than compile time(its always 'second's' getdouble which is invoked).
So there are some qualifications to this particular item in 'Effective Java' that I did not get.
Please help clarify what was meant by 'resolving overloading at compile-time'.
How is the above different from this:
....
class fourth{
public static String getCollection(Set<?> s){
return "Set";
}
public static String getCollection(Collection<?> c){
return "Collection";
}
public String getiCollection(Set<?> s){
return "Set";
}
public String getiCollection(Collection<?> c){
return "Collection";
}
public static void main(String[] args){
Collection<String> c=new HashSet<String>();
System.out.println(fourth.getCollection(c));
fourth f=new fourth();
System.out.println(f.getiCollection(c));
...
This answer in this case is always 'Collection' rather than the actual run-time type.
The declared type of s is parentsecond so when the compiler runs through the code, it will assign the method that takes parentsecond as an argument
public static void calloverload(parentsecond s)...
However, overriding is a different subject. The actual type of the instance s is second and so second's getdouble method will be executed. This is a case of polymorphism. In java, polymorphism is accomplished through late-binding.
To quote from this answer:
The JLS states in §8.4.9 Overloading:
When a method is invoked (§15.12), the number of actual arguments (and any explicit type arguments) and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2).
If the method that is to be invoked is an instance method, the actual method to be invoked will be determined at run time, using dynamic method lookup (§15.12.4).
The argument is s and its compile time type is parentsecond. Its run time type is second.
EDIT To answer the addition to your question, see point 1 above. Nothing needs to be evaluated at run time. The compiler uses the compile time type, Collection, in both calls.
The point is not that the compiler can't figure it out; the point is that overloading is confusing for the programmer, and is therefore likely to cause bugs.
If you need to pull out the JLS in order to figure out which method is the most specific match to the way you are calling it, then every maintenance programmer who ever looks at that code will have to go through the same exercise.
Hence, the suggestion that overloads should have different numbers of parameters, or at least parameter types that are not interconvertible.
The specific danger of "resolving overloading at compile time" is this. Suppose I have:
void method(List a) { }
void method(Collection a) { }
Then, these two calls will do different things:
List list = new ArrayList();
method(list);
method((Collection)list);
This is highly unintuitive (hence confusing, hence a source of bugs) for the programmer.
Related
In the code below I get a compiler error at b.printname();. As I understand it the error is to do with the fact that the compiler is effectively operating in a non polymorphic way( i.e. the compiler is essentially only choosing to look at the left side of the operand and therefore b is a Question). Since b is of type Question and since Question does not have a no-args printName method you get a compilation error. Is that correct?
Now assuming that is correct, my question is why? Surely the compiler should know that Question b is referring to an object that does in fact support the no-args printName method? E.g. if you look at how the compiler behaves in terms of casting there are examples where the compiler, for lack of a better word, acts polymorphicly or to put it a different way the compiler knows what's going on in terms of the right hand side of the operand and acts upon that knowledge. An example would be if an interface type refers to an object that implements the interface, then the compiler looks at the right hand side of the statement (i.e. the object that implements the interface) and decides no cast is required. So why doesn't the compiler act that way here, why doesn't it look and see that the object in question is actually a Blue and that a Blue does indeed support the no-arg method printName?
public class Polymorf3 {
public static void main(String[] args){
Polymorf3 me = new Polymorf3();
me.doStuff();
}
public void doStuff() {
Bat a = new Bat();
Question b = new Blue();
//a.printName();
a.printName(a.name);
b.printName(); // Compiler Error:Required String Found no args
}
abstract class Question {
String name="Question_name";
public void printName(String name){ System.out.println(name);}
}
class Bat extends Question {
String name = "Bat_Bruce";
//public void printName(){ System.out.println(name);}
}
class Blue extends Question {
String name = "Clark";
public void printName() {System.out.println(name);}
}
}
Though b is of type Blue, since you declared it as Question b = new Blue();, the compiler treats it as type Question, and thus that's the only interface available to it without an explicit cast:
((Blue)b).printName();
Alternatively, you can declare it as Blue b = new Blue(); and b.printName(); will not throw a compile time error.
Essentially what's happening here is that you're declaring your new variable b at a higher level of abstraction, so the only printName method available to b is the one in the higher level of abstraction, the one with the args.
Edit:
OP asked why the compiler treats b as a Question even though it's initialized as Blue. Consider the following:
Question q = new Blue();
// ... some other code...
q = new Bat(); // Valid!!
q.printName("some string");
Now consider that tomorrow, some other developer comes in and changes it to the following:
Blue q = new Blue();
// ... some other code...
q = new Bat(); // Invalid!! Compiler error
q.printName("some string");
Declaring a variable at the highest level of abstraction required for your operation means you can later change the implementation more easily and without affecting all the rest of your code. Thus, it should be clear why the Java compiler is treating b as a Question. It's because b can, at any time, become an instance of Blue or Bat, so treating it as the implementation (Blue or Bat) would violate the contract of the Question interface by allowing some other non-arg getName method.
You seem to have misunderstood what polymorphism means. It means that you can treat an instance of the derived class as if it was an instance of the base class. That includes not calling methods on it that the base class doesn't provide. The variable type informs what methods you can call, and the instantiation type determines what implementations of those methods are run.
By putting your Blue instance in a Question variable, you are asking to treat it like a Question. If you wanted to call methods on your Question variable that are not provided by the Question class, then why have it be a Question variable at all? If you could call derived-class methods on a base class variable, it would not be a base class variable.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
If i use so
class Test {
public Test() {
System.out.println("constructor");
}
}
public class MainClass {
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = new Test();
}
}
I get 2 outputs
constructor
constructor
But if I add void to constructor (public void Test()) - output is empty. Why is so strange ?
It's not strange, it's its normal behaviour. Constructor does not have a return type
public Test() {
System.out.println("constructor");
}
is a constructor, but
public void Test() {
System.out.println("constructor");
}
is a simple method that you can call using t1.Test().
This page lists the differences between constructors and methods:
1) First difference between method vs constructor in Java is that name of constructor must be same with name of the Class but there is no such requirement for method in Java. methods can have any arbitrary name in Java.
2) Second difference between method and constructor in Java is that constructor doesn't have any return type but method has return type and return something unless its void.
3) Third difference between constructor and method in Java is that Constructors are chained and they are called in a particular order, there is no such facility for methods.
4) Unlike method, constructor, yet declared in class doesn't considered as member of Class. Constructors are not inherited by child classes but methods are inherited by child classes until they are made private. on which case they are only visible in class on which they are declared. Similarly private constructor means you can not create object of that class from outside, this is one of the technique used to implement Singleton pattern in Java.
5) Another difference between method and constructor in Java is that special keyword this and super is used to call constructor explicitly. no such thing for method, they have there own name which can be used to call them.
Because if you add void to the constructor that is no longer a constructor. It's just a method that happens to have the same name as the class.
Then, you could ask "but how can I call the constructor if one doesn't exists?" Well, every class has implicit, no-args constructor.
Conclusion: constructor must not have a return type.
Constructors don't have a return type .Methods have return type. If you add void() then it turns to a method . To invoke the method you need to call it .
t1.test();
Its java language specification.
Docs saying
A class contains constructors that are invoked to create objects from the class blueprint. Constructor declarations look like method declarations—except that they use the name of the class and have no return type.
When you write:
public Test()
{
System.out.println("constructor");
}
This is definitely a constructor. And, as you create first object of Test class by writing:
Test t1 = new Test();
This would call your constructor for the first time, and the code you have written in print statement, that is, constructor would be printed on console.
Remember, constructors are automatically called when you create an object of the class.
Second time you create object by writing:
Test t2 = new Test();
This would call the same constructor, and print the same "constructor" on screen, but it would be second time.
So you get the answer as-
constructor
constructor
In the second case, when you write:
public void test()
{
System.out.println("constructor");
}
your compiler would treat it as a method rather than a constructor.
Even if void does not return anything, it is a "return-type" and constructors can never have a return type, never.
This does not mean that they do not return you anything, but they just do not have a return type.
So, a method is not called automatically when the object of the class is created. So, you should not expect same result.
Now, you get an empty output because compiler provides a dummy/default constructor to every class, even if you do not define it. And, this default constructor would be called everytime you create a object of the class, no matter if you call it explicitly or not!
a default constructor can be thought of written somewhere as:
test() { }
so now you can imagine what happens when you create two objects, program would compile and run correctly, returning empty output to you!
I hope that helped you.
Because constructors don't have a return type. What you create when you add a void return type is a method named Test() that returns nothing.
The compiler gives you a no-arg constructor, since you didn't write any, and that does nothing because it's not the method you created.
A java constructor has the same name as the name of the class to which it belongs. Constructor’s syntax does not include a return type, since constructors never return a value.
public Test() {
System.out.println("constructor");
}
If you add return type to Constructor then it will not be a constructor no longer. It is something like a method.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
My brother works as a teacher in secondary school, and is grading an exam. He asked the question: "What is the purpose of a constructor?"
So now there were some answers like "The constrcutor creates an object..."
Of course he wanted to see something like "The constructor is called after the object's instanciation and is used to initialize an object's member variables..." (just an example)
The problem is that there is a lot of literature where the authors write that the constructor in Java creates the object, and in general most authors seem to avoid a detailed explanation of the whole process.
I think it works like this:
The class constructor is called as an operand of the new operator, since "the name of the constructor provides the name of the class to instantiate." (see http://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html)
But before executing this constructor the new operator instantiates the class (allocates memory etc.) and sets the member variables to their default values.
Then the constructor is executed and initializes member variables for example.
In the last step the new operator returns a reference to the object.
But I really don't know if this is actually right, and if things happen in the exact order.
Does anyone know about object creation in detail? How does it work if you create a subclass? Is the superclass created first, its constructor called next, then the subclass merged into the existing construct somehow, and its constructor called then? Could someone somehow argue that a constructor "CREATES" an object?
I am really looking forward to reading your answers!
The gory details are covered in the Java Language Spec, here is the basics that you need to know on an every day level (continues in the next section, I pointed you at the class initialization which happens the first time a class has new called on it (there are other ways for it to happen too)).
new allocates the memory for the object and initializes it to 0, null, false (depending on the type). That is why all the instance variables are guaranteed to have initial values.
Assuming new succeeds the constructor is called to allow the programmer to perform other initialization/tasks.
The first thing that a constructor does is call the parent constructor (super(...)). That happens all the way up the hierarchy until it reaches java.lang.Object which has no parent.
Before the constructor is executed any instance initialization blocks are run, followed by any instance variables that have assignment operators.
There is a special case if an instance variable is marked as final and has an assignment operator which seems to happen before the call to super if I remember right (there is some trick to it).
All of this is why you should never refer to this.method() (implicitly or explicitly) or pass this out of the constructor because you will be making use of an unfinished object.
Your explanation is correct, as far as I know.
The main idea behind constructors is that you can enforce valid states for an object.
Consider a class called "Rational" with two properties: numerator (int) and denominator (int)
The code would look like this (I've omitted the getters and setters for brevity)
public class Rational {
private int numerator;
private int denominator;
public Rational(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public double getRationalValue() {
return (double) numerator / denominator;
}
public static void main(String[] args) {
Rational oneFourth = new Rational(1, 4);
System.out.println(oneFourth.getRationalValue());
}
}
As you can see, I've written a constructor that "demands" values for the numerator and denominator. If you only had a default constructor, anyone could make instances of Rational without specifying a numerator or denominator, and if you don't specify a value for an int variable, they are initialized at zero. And everyone knows the universe collapses if you divide by zero, so we'd like to avoid that.
Anyway, constructors don't make the object, as you correctly explained. You should see them more as a method that is called "post construction".
When it comes to base classes, the constructor of the base class is always called first. This ensures that you can access protected properties of the base class in your subclass constructor.
Since every class in Java inherits from Object, the Object constructor is always called first.
The following snippet:
public class Base {
protected String baseProperty;
public Base() {
System.out.println("In base constructor");
this.baseProperty = "This gets initialized first";
}
static class Sub extends Base {
private String subProperty;
Sub() {
System.out.println("In sub constructor, baseProperty = " + baseProperty);
}
}
public static void main(String args[]) {
Base base = new Sub();
}
}
prints:
In base constructor
In sub constructor, baseProperty = This gets initialized first
Right from the specification to clear your doubt about the new and constructor role:
Creating Objects
As you know, a class provides the blueprint for objects; you create an object from a class. Each of the following statements taken from the CreateObjectDemo program creates an object and assigns it to a variable:
Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);
The first line creates an object of the Point class, and the second and third lines each create an object of the Rectangle class.
Each of these statements has three parts (discussed in detail below):
Declaration: The code set in bold are all variable declarations that associate a variable name with an object type.
Instantiation: The new keyword is a Java operator that creates the object.
Initialization: The new operator is followed by a call to a constructor, which initializes the new object.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Method Overloading for NULL parameter
In the code below the output is
String
and if I remove the method with the parameter of type String then the output is
Object
I know how overloading of methods acts when the parameter types don't match exactly but I can not understand how null can be treated as an Object and/or a String parameter.
What is the explanation for this?
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
public static void main(String[] args) {
m1(null);
}
}
It always uses the most specific method according to the Java specs, section 15.12.2.5.
The intro is reasonably specific about it:
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
Generally speaking, and at least for code readability, it's always best to try to be as explicit as possible. You could cast your null into the type that matches the signature you want to call. But that's definitely a questionable practice. It assumes everyone knows this rule and makes the code more difficult to read.
But it's a good academic question, so I +1 your question.
When multiple overloads match a signature, Java picks the most specific method from among them.
The value of null matches both Object and String, but String is a subclass of Object, so String is picked. If you add another overload with a sibling of String in the class hierarchy, you'd get a compile error.\
// DOES NOT COMPILE
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
static void m1(Integer x) {
System.out.print("Integer");
}
public static void main(String[] args) {
m1(null);
}
}
Here is a link to a post that discusses your code example at some length.
If you need to force the call of a aprticular overloaded method when passing null as parameter, you have to cast it, like this:
m1((String)null);
By doing this, you make sure you're calling the correct overloaded version of the method.
You have to set the type of null to tell Java what function you want to call.
So you do: m1((Object) null); to call the implementation with the Object parameter and you do m1((String) null); to call the other one.
1. As String is also an object the JVM got confused to call which method at runtime.
2. If you want to specify which method to call at runtime, you can do this by explicit casting
eg:
m1((String)null);
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I understand what is java method invocation and have practiced many examples using it.
I want to know what is the practical situation or need of this concept.
It would be of great help if anyone could give a real world scenario where it is used and
what would happen if this concept would have not been there?
Here is an example. Suppose we have 2 classes:
class A {
public String getName() {
return "A";
}
}
class B extends A {
public String getName() {
return "B";
}
}
If we now do the following:
public static void main(String[] args) {
A myA = new B();
System.out.println(myA.getName());
}
we get the result
B
If Java didn't have virtual method invocation, it would determine at compile time that the getName() to be called is the one that belongs to the A class. Since it doesn't, but determines this at runtime depending on the actual class that myA points to, we get the above result.
[EDIT to add (slightly contrived) example]
You could use this feature to write a method that takes any number of Objects as argument and prints them like this:
public void printObjects(Object... objects) {
for (Object o: objects) {
System.out.println(o.toString());
}
}
This will work for any mix of Objects. If Java didn't have virtual method invocation, all Objects would be printed using Object´s toString() which isn't very readable. Now instead, the toString() of each actual class will be used, meaning that the printout will usually be much more readable.
OK, I'll try to provide a simple example. You are writing a method that will fill a caller-supplied list:
public void fill(List l) {
list.add("I just filled the list!");
}
Now, one caller wants to use a linked list; another one prefers a list implementation based on an array. There will be other callers with even more list implementations that you've never even heard of. These are totally different objects. Propose a solution that achieves this without relying on virtual methods.
Without virtual methods this would mean that the type List would already need to have the method add implemented. Even if you had a subtype ArrayList which had an overridden method, the compiler (and the runtime!) would simply ignore that method and use the one in List. It would be impossible to use different List implementations that conform to the same interface; it would be impossible to reuse that line of code in the method fill since it would work only with the method in the type List.
So you see, the whole idea of type hierarchy wouldn't make a lot of sense; interfaces and abstract classes couldn't even exist. The whole of Java would break down into shards without that one feature of virtual methods.