I am trying to simulate a kind of pointer used in another obscure programming paradigm, so I can port some code to Java. The other language is not object-oriented, and was loosely inspired by Pascal.
In the original language, we can write code like this. First, working with text.
// Start with text.
Text myVar = "Bonjour"
Pointer myPointer = ->myVar // Referencing a string variable, storing the reference in another variable of type `Pointer`.
Message( myPointer-> ) // Dereferencing the pointer, to retrieve `myVar`, and pass the string to a command `Display` that displays the message on screen in a dialog box.
Then, switching to numbers.
// Switch gears, to work with an number.
Integer vResult = ( Random % ( vEnd - vStart + 1 ) ) + vStart // Generate random number.
myPointer = ->vResult // The same pointer now points to numeric variable rather than a textual variable.
We can assign a pointer by the text of a variable name.
myPointer = Get pointer( "var" + String($i) ) // Generate pointer variable named `var1`, or `var2`, etc.
We can ask the pointer for a code number representing the data type of the value to which it is pointing (the data type of the referent).
typeCodeNumber = Type( myPointer ) // Returns 11 for an integer, 22 for text.
In this other language, the compiler does provide for type-safety. But when using pointers in this fashion, we sacrifice type-safety. The compiler emits a warning that the code usage is ambiguous with regard to type.
My idea to port this code is to define a XPointer class as well as classes for the types such as XText and XInteger.
I need to hold a reference to an object of any of a dozen specific known types, including to another pointer. I can hard-code the dozen types, no need to be open to all types.
These dozen types do not share an interface nor abstract class other than Object. And even if they did share an interface/superclass, I do not want them returned as a superclass but as their original concrete class. As they entered the pointer, so should they emerge from the pointer.
My current plan is to define a XPointer class in Java with a pair of reference and dereference methods:
XPointer::ref( x ) where you pass an object of Dog, Truck, or Sculpture class, or even another XPointer object.
XPointer::deref ⇒ x where x is an object recognized as its original type, a Dog, a Truck, or a Sculpture or even another XPointer object, rather than a mere Object object.
➥ Is there some way to do this Java? Perhaps with Generics?
➥ If not possible in Java, I could reluctantly switch to Kotlin. Can this pointer functionality can be done in Kotlin running on a JVM?
So code my look like this:
XPointer p = new XPointer() ; // Points to nothing, null.
p.ref( new Dog() ) ; // Pointer points to a `Dog` object.
p.deref().bark() ; // Pointer can retrieve the `Dog` as such, a `Dog` object.
p.ref( someTruck ) ; // The pointer can switch to pointing to an object of an entirely different type. The `Dog` object has been replaced by a `Truck` object.
p.deref().honk() ; // Dereference the stored `Truck` object as such.
And a pointer to a pointer.
XPointer p2 = new XPointer() ; // Points to nothing, null.
p2.ref( p ) ; // 2nd pointer points to a pointer that points to a `Truck` object.
p2.deref().deref().honk() ; // Dereference the stored `Truck` object as such.
If there is a better route towards such a pointer-simulation, I am open to suggestions. Elegance is not required; any hack will do.
This is known as a union or a variant type (see Boost.Variant in C++). The latter is specially handy as it's a type-safe container for a heterogeneous set of types and stands the closest to your description of a type of code you are porting from. Since Java does not support templates - no, generics are not templates - you won't get exactly what you are looking for.
The Optional type is the simplest case of two types: a type T and a Null. Given your requirement to store more than a type T or Null, it won't work for you.
You may want to check out the JavaSealedUnions. In addition, Kotlin provides a concept of sealed classes, helpful to limit a value to one of the types from a constrained set.
Good luck!
My apologies for the long answer.
I don't think you can achieve exactly what you want with Generics without losing type safety.
For the next line to work, Java needs to know there is a Truck returned by the defer() method so it can call honk() on that object.
p.deref().honk();
But if you would use Java Generics, than that infers type erasure on compilation.
The solution would imply adding a generic type like Pointer<Truck>, but we can't since you want to be able to add a dozen specific known types and a Pointer.
However ... since you yourself write that line like that, specifically making a call to bark() or honk(),
it implies you already know that the Pointer references a Dog or Truck object at that point in your code.
Using that assumption, Generics and a modification to defer(), you can get pretty close to a solution.
Let's say we have these classes, which have no links in any way.
public class Dog {
public void bark() {
System.out.println("Bark ...");
}
}
public class Truck {
public void honk() {
System.out.println("Honk ...");
}
}
Then we need a Pointer class like this, where the deref() method needs a Class parameter to know which type to return.
public class Pointer {
private Object myObj;
public <T> void ref(T myObject) {
this.myObj = myObject;
}
public <T> T deref(Class<T> myClazz) {
try {
return myClazz.cast(myObj);
} catch(ClassCastException e) {
return null;
}
}
}
Then you can do the following
public static void main(String[] args) {
Pointer pointer = new Pointer();
Dog dog = new Dog();
pointer.ref(dog); // Reference to a Dog
pointer.deref(Dog.class).bark();
Truck truck = new Truck();
pointer.ref(truck); // Reference to a Truck
pointer.deref(Truck.class).honk();
Pointer subPointer = new Pointer();
pointer.ref(subPointer); // Reference to another pointer
subPointer.ref(truck); // Other pointer references a Truck
pointer.deref(Pointer.class).deref(Truck.class).honk();
subPointer.ref(dog); // Other pointer references a Dog
pointer.deref(Pointer.class).deref(Dog.class).bark();
pointer.ref(null); // Clears the reference
Truck bulldog = new Truck();
pointer.ref(bulldog);
pointer.deref(Dog.class).bark(); // Is allowed, but will cause a NullPointerException
}
This will print out:
Bark ...
Honk ...
Honk ...
Bark ...
Exception in thread "main" java.lang.NullPointerException at Pointer.main(Pointer.java:39)
If you need to limit your Pointer reference to only your dozen specific known types and the Pointer class itself, then you need to extend them with a super class (for example Pointerable) and modify the ref() method accordingly.
Then you can prevent types that don't extend this super class to be referenced by your Pointer.
Example:
public abstract class Pointerable { }
public class Dog extends Pointerable {
public void bark() {
System.out.println("Bark ...");
}
}
public class Pointer extends Pointerable {
private Object myObj;
public <T extends Pointerable> void ref(T myObject) {
this.myObj = myObject;
}
public <T extends Pointerable> T deref(Class<T> myClazz) {
try {
return myClazz.cast(myObj);
} catch(ClassCastException e) {
return null;
}
}
}
This is the best I can come up with. I think you can't easily make a common Type, without it being the parent of all classes (like Object).
Also conversion is hard given the type system, you can possibly mimic it by not allowing to reassign pointers of different type, but just generating a new pointer every time you do a get. if you don't like to know the type itself you can use var in modern java to hide the type difference.
public class Types {
public static void main(String[] args) {
var p = new PascalPointer<>(new PascalInt());
PascalInt i = p.get();
var p2 = new PascalPointer<>(i.toPStr()); // mimic generics by type inference.
PascalString s = p2.get();
PascalPointer<PascalType> genericPointer = new PascalPointer<>(s);
genericPointer.set(i);
var i2 = (PascalInt) genericPointer.get();
}
public interface PascalType { }
public static class PascalInt implements PascalType {
// cast
public PascalString toPStr() {
return new PascalString(); // hide a new to do a conversion instead of a cast really.
}
}
public static class PascalString implements PascalType { }
public static class PascalPointer<T extends PascalType> {
T t;
public PascalPointer(T t) { this.t = t; }
public T get() { return t;}
public void set(T t) {this.t = t;}
}
}
This probably breaks down when you want to have an Int view of a string and you update the string (as I am copying here).
Related
Say I have a generic class Foo which can hold an object of type T. Furthermore, let's say I only want to be able to instantiate the class with objects that are one of two types. Finally, let's say that the lowest common upper bound of these two types is a type that has many more subclasses than those two types that I want to allow, so I can't simply specify an upper bound for the type parameter (as in class Foo<T extends Something>), because then I would allow to instantiate the class with other types than the two I expect.
For illustration, let's say I want Foo to hold only either a String or an Integer. The lowest common upper bound is Object, so specifying an upper bound won't do the trick.
Certainly, I could do something along the lines of
class Foo<T> {
private T obj;
public Foo(T obj) throws IllegalArgumentException {
if (!(obj instanceof String || obj instanceof Integer)) {
throw new IllegalArgumentException("...");
}
this.obj = obj;
}
}
However, in this case, I can still call the constructor with any object; if I try to instantiate it with something that is neither a String nor an Integer, I will get an exception at runtime.
I would like to do better. I would like the compiler to infer statically (i.e., at compile time) that I can only instantiate this class with objects that are either String or Integer.
I was thinking something along those lines might do the trick:
class Foo<T> {
private T obj;
public Foo(String s) {
this((T) s);
}
public Foo(Integer i) {
this((T) i);
}
private Foo(T obj) {
this.obj = obj;
}
}
This works, but it looks really, really odd. The compiler warns (understandably) about unchecked casts. Of course I could suppress those warnings, but I feel this is not the way to go. In addition, it looks like the compiler can't actually infer the type T. I was surprised to find that, with the latter definition of class Foo, I could do this, for instance:
Foo<Character> foo = new Foo<>("hello");
Of course, the type parameter should be String here, not Character. But the compiler lets me get away with the above assignment.
Is there a way to achieve what I want, and if yes, how?
Side question: why does the compiler let me get away with the assignment to an object of type Foo<Character> above without even so much as a warning (when using the latter definition of class Foo)? :)
Try using static factory method to prevent compiler warning.
class Foo<T> {
private T obj;
public static Foo<String> of(String s) {
return new Foo<>(s);
}
public static Foo<Integer> of(Integer i) {
return new Foo<>(i);
}
private Foo(T obj) {
this.obj = obj;
}
}
Now you create instance using:
Foo<String> foos = Foo.of("hello");
Foo<Integer> fooi = Foo.of(42);
Foo<Character> fooc = Foo.of('a'); // Compile error
However the following are still valid since you can declare a Foo of any type T, but not instantiate it:
Foo<Character> fooc2;
Foo<Character> fooc3 = null;
Foo<Object> fooob1;
Foo<Object> fooob2 = null;
one word: interface. You want your Z to wrap either A or B. Create an interface implementing the smallest common denominator of A and B. Make your A and B implement that interface. There's no other sound way to do that, AFAIK. What you already did with your constructors etc. is the only other possibility, but it comes with the caveats you already noticed (having to use either unchecked casts, or static factory wrappers or other code smells).
note: If you can't directly modify A and/or B, create wrapper classes WA and WBfor them beforehand.
example:
interface Wrapper {
/* either a marker interface, or a real one - define common methods here */
}
class WInt implements Wrapper {
private int value;
public WInt( int value ) { this.value = value; }
}
class WString implements Wrapper {
private String value;
public WString( String value ) { this.value = value; }
}
class Foo<T> {
private Wrapper w;
public Foo(Wrapper w) { this.w = w; }
}
because you call your private Foo(T obj) due to diamond type inference. As such, it's equal to calling Foo<Character> foo = new Foo<Character>("hello");
Long story short: You are trying to create a union of two classes in java generics which is not possible but there are some workarounds.
See this post
Well the compiler uses the Character class in T parameter. Then the String constructor is used where String is casted to T (Character in this case).
Trying to use the private field obj as a Character will most likely result in an error as the saved value is an instance of the final class String.
Generics is not suitable here.
Generics are used when any class can be used as the type. If you only allow Integer and String, you should not use generics. Create two classes FooInteger and FooString instead.
The implementations should be pretty different anyway. Since Integers and Strings are very different things and you would probably handle them differently. "But I am handling them the same way!" you said. Well then what's wrong with Foo<Double> or Foo<Bar>. If you can handle Integer and String with the same implementation, you probably can handle Bar and Double and anything else the same way as well.
Regarding your second question, the compiler will see that you want to create a Foo<Character>, so it tries to find a suitable overload. And it finds the Foo(T) overload to call, so the statement is perfectly fine as far as the compiler is concerned.
Let's say we have the following program:
class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}
public class Main {
public static void main(String[] args) {
Fruit[] fruit = new Apple[10];
try {
fruit[0] = new Fruit(); // ArrayStoreException
fruit[0] = new Orange(); // ArrayStoreException
} catch(Exception e) { System.out.println(e); }
}
}
Based on the Java documentation:
Thrown to indicate that an attempt has been made to store the wrong
type of object into an array of objects.
I've read here that
When array is created it remembers what type of data it is meant to store.
If the array remembers what type of data it contains, it means that it KNEW the type of data it contains. But the snippet I posted is correctly compiled, so at compile time the array apparently doesn't know what type contains.
My questions are:
Why is the ArrayStoreException thrown only at runtime?
What information are missing to the compiler to realise that that assignment is not possible?
Is there any cases in which such code is correct so no ArrayStoreException is thrown?
If the array remembers what type of data it contains, it means that it KNEW the type of data it contains.
At execution time, yes... just like at execution time, the type of an object is known:
Object x = "foo";
// The compiler won't let you call x.length() here, because the variable
// x is of type Object, not String.
The alternative would be to make very many array assignments implicitly throw a checked exception. That would be awful - similar to making NullPointerException checked.
What information are missing to the compiler to realise that that assignment is not possible?
Arrays are covariant, as you've seen. When the compiler sees an assignment into a Fruit[] of an Apple, it can't know what the actual type of that array is going to be. If it's Fruit[] or Apple[], that's fine. If it's Orange[] it's not. That information is only present at execution time - again, just like the compiler doesn't know whether an expression is definitely not null.
Is there any cases in which such code is correct so no ArrayStoreException is thrown?
Well if you have an array with a compile-time element of a final class, then you can't have any lower variance. So for example:
public void foo(String[] array) {
array[0] = "x";
}
That can throw exceptions due to array being null or empty, but it will never throw an ArrayStoreException, because String is final. The implementation could never be a SubclassOfString[].
It's a runtime exception for the same reason ClassCastException is. It's not always possible to tell at compile time whether the type is what you expect or not.
Consider this example:
void method1() {
Fruit[] fruits = getFruits();
fruits[0] = new Orange();
}
Fruit[] getFruits() {
if (someCondition) {
return new Apple[5];
} else {
return new Orange[5];
}
}
There's no way for the compiler to know what state someCondition will be in when you call getFruits(). Hence the runtime exception.
When array is created it remembers what type of data it is meant to
store.
The array "remembers" only what type it actually contains during runtime.
First the array is declared, in this case as an array of Fruit.
Then the array is created, in this case as an array of Apple.
Creation is made during runtime, but the compiler is designed only to verify that the array only is assigned objects of the type it is declared as. There are so many things that can occur during runtime.
Consider the following code:
class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}
public class Main {
public static void main(String[] args) {
Fruit[] fruit = new Apple[10];
boolean alt = (Math.random() < 0.5);
try {
fruit[0] = fruitFactory(alt);
} catch(Exception e) { System.out.println(e); }
}
private static Fruit fruitFactory(boolean apple) {
if (apple) {
return new Apple();
} else {
return new Orange();
}
}
}
The code is identical to your except that the fruit[0] is assigned a value by the fruitFactory method. There is no way the compiler can tell if the boolean alt is going to be true or false.
What information are missing to the compiler to realise that that
assignment is not possible?
As said - the compiler cannot tell if the assignment is possible or not.
Is there any cases in which such code is correct so no
ArrayStoreException is thrown?
Yes, in 50 % of the cases in the code above. You either have to verify that the object assigned is the same as the array or catch the exception.
At your case, apple and orange are implicitly casted into fruit, because they are subclass of fruit. That's why it"s not throwing an exception, and this behavior is one of the OOP basics : it's called polymorphism.
if the array was declared as an apple array and you try to add fruit inside(the opposite of your case), then an exception will be thrown : because you can implicitly cast only from child to parent(the cast from parent to child should be explicit).
public class Maryland extends State { Maryland() { /* null constructor */ }
public void printMe() { System.out.println("Read it."); }
public static void main(String[] args) {
Region mid = new State();
State md = new Maryland();
Object obj = new Place();
Place usa = new Region();
md.printMe();
mid.printMe();
((Place) obj).printMe();
obj = md;
((Maryland) obj).printMe();
obj = usa;
((Place) obj).printMe();
usa = md;
((Place) usa).printMe();
}
}
class State extends Region {
State() { /* null constructor */ }
public void printMe() { System.out.println("Ship it."); }
}
class Region extends Place {
Region() { /* null constructor */ }
public void printMe() { System.out.println("Box it."); }
}
class Place extends Object {
Place() { /* null constructor */ }
public void printMe() { System.out.println("Buy it."); }
}
Hi There.
I'm trying to understand the behaviour of the above main method which prints the following output when run.
Read it.
Ship it.
Buy it.
Read it.
Box it.
Read it.
I'm particularly struggling to understand the output of the last two printMe methods in the main function.
My understanding is that the first two print me operations will use there super classes printMe method as the objects have not been explicitly downcast to the sub class and thus are considered to be State and Region objects respectively by the Java compiler.
I also believe I understand the next two outputs in which the classes are downcast and thus the subclass printMe functions will override the superclass functions.
However I am struggling to understand what is occurring in the last two printMe methods. I can see that the variable obj is initially declared as an Object and then downcast as a Place is assigned a reference to the usa object(of type Place). So why is the output then of type region in this instance? I feel I am missing fundamental here in my understanding.
In Java, instance method calls follow inheritance. No matter what the reference type is, it will call the method of the type of the actual object.
The type of the reference only determine which methods the compiler knows you can call. e.g.
String hi = "Hello";
Object A = hi;
String hiToString = A.toString(); // calls String.toString();
int l = A.length(); // won't compile even though the String in A has a length() method.
Note: for static methods, the instance is ignored and it is the compile time type which determines which method is called.
In Java, non-static methods are called with late-binding, which means we cannot make sure which function it will call until run-time.
My understanding is that the first two print me operations will use there super classes printMe method as the objects have not been explicitly downcast to the sub class and thus are considered to be State and Region objects respectively by the Java compiler.
Explicitly downcast does nothing in this code. Downcast is actually performed.
Object md is still a reference to State and Object mid is a reference of Region. Compiler will never know which printMe() will be called. It only checks that State and Region classes have the function printMe() or not.
At run-time, when the md.printMe() is called, JVM will check the Runtime type information (RTTI) of md, and know it is a Object of State class. Therefore, the printMe() function in the State class is called, no matter what md is declared. (Of course, you need to override the printMe() in the State class. If you don't, State class will inherit the printMe() function from its superclass Place, and the printMe() function in Place class will be called. You can check this by removing the printMe() function in your State class.)
According to these rules, the output is reasonable.
The type cast in ((Place) obj).printMe() is needed just because in Object class, there's no printMe() function in it. Still, the compiler can't make sure which function ((Place) obj).printMe() will called, it is decided at run-time. For example, if you change your ((Maryland) obj).printMe(); to ((Place) obj).printMe();, the output is still the same.
For static methods, these rules will not fit. You can read more information about them with the keywords "Overloading, Overriding and Hiding". These terminologies will help you to understand the inheritance system in Java.
Object aThing = new Integer(25);
The method call aThing.intValue() is a compiler error. Why doesn't polymorphism work in this case?
Also there's a related statement in my textbook that is a bit convoluted:
The type of reference, not the type of the object referenced, determines that operations can be performed.
Can you briefly elaborate on that?
Where as Computer[] labComputers = new Computer[10]; works with polymorphism
public class Computer {
int ram;
public Computer(int rm){
ram= rm;
}
public String toString(){
String result = "ram is " + ram;
return result;
}
}
public class Notebook extends Computer{
int size;
public Notebook(int rm, int sz){
super(rm);
size = sz;
}
#Override
public String toString(){
String result = super.toString() + " size is " + size;
return result;
}
}
Added:
I believe somewhere in the middle, there would be
labComputer[1] = new Notebook(2,15);
labComputer[2] = new Computer(2);
For the method call labComputers[1].toString(), polymophism ensures that the correct toString is called. In my mind labComputer[1] = new Notebook(2,15); is equivalent to Object o = new Integer(25);. But polymorphism worked for my Computer example not in the Object-Integer example. Why?
It won't work because your variable is from Object class, so you can only use methods in the Object class. If you want to use it as an Integer, you should first do a (down) type casting:
Integer aInteger = (Integer)aThing;
//it could maybe work
aInteger.intValue();
Now, why could maybe work? Because downcasting could throw a ClassCastException if the type casting won't work.
Based in your example, I would post a basic code to show how polymophism works:
class Animal {
public void move() {
System.out.println("I'm an animal and I can move.");
}
}
class Cat extends Animal {
//this means a Cat would change the move behavior from the Animal instance
#Override
public void move() {
System.out.println("I'm a cat and I can move.");
}
}
class Dog extends Animal {
//this means a Cat would change the move behavior from the Animal instance
#Override
public void move() {
System.out.println("I'm a dog and I like to run.");
}
public void bark() {
System.out.println("I can bark!");
}
}
public class AnimalTest {
public static void main(String[] args) {
//it will take the behavior of the Animal class reference
Animal animal = new Animal();
//it will take the behavior of the Cat class reference
Animal cat = new Cat();
//it will take the behavior of the Dog class reference
Animal dog = new Dog();
//this will invoke the Animal#move method
animal.move();
//this will invoke the Cat#move method because it was overriden in the Cat class
cat.move();
//this will invoke the Dog#move method because it was overriden in the Dog class
dog.move();
//this line won't compile if uncommented because not all animals can bark.
//dog.bark();
//if you want to make the dog barks, then you should use the downcasting
((Dog)dog).bark();
//note that this will only work for Dog class reference, not for any other class
//uncomment this line and the code will compile but throw a ClassCastException
//((Dog)cat).bark();
}
}
Because even though Integer is an Object, Object is not an Integer and therefore it doesn't have Integer's methods, only Object's.
The type of reference, not the type of the object referenced, determines that operations can be performed.
By that they mean that even though the object that is referenced contains more functionality, if the type of the reference is different from the type of the object, then only the functionality of they type of the reference will be available.
In the following:
Object aThing = new Integer(25);
the type of aThing is declared as Object. Even though the implementation contains more than that, whatever else the implementation contains is not visible anymore, because the type of the variable is not Integer, but Object. Both Object and Integer have methods in common, but you can only access the ones provided by Object from now on, because nobody other than you know that this is really an Integer, not just an Object.
In the second example they mean that even though both Object and Integer have methods in common, when you call one of the methods, the method of the actual type will be called. So in this case, if you call toString() on aThing, you will call Integer's toString() method, not Object's. Therefore this is only an access issue. The fact that you declare it as an Object doesn't mean that you will get Object's methods to respond to calls, it only means that whatever methods that are present in Integer and not in Object will just be unavailable.
Example:
class Computer {
public int getInstalledOperatingSystems() { return 3; }
}
class Desktop extends Computer {
public String getShapeOfCase() { ... }
}
class Notebook extends Computer {
public int getInstalledOperatingSystems() { return 1; }
public String getBrand() { ... }
public void closeLid() { ... }
}
Now let's create a Notebook:
Notebook n = new Notebook();
Suppose that you have the following method:
public String showStatistics(Computer computer) {
result = "Operating systems: " + computer.getInstalledOperatingSystems();
return result;
}
If you call this method with the Notebook you defined above:
showStatistics(n);
then the method will receive the Notebook, because a Notebook is a Computer. It can call the Notebook's getInstalledOperatingSystems() method, because any Computer has that method. When it calls it, it will receive 1 as a result, because Notebook overrides Computer's implementation. But showStatistics() will not be able to call any other method that Notebook provides, because it doesn't know that it's being passed a Notebook. For all it cares, it has a Computer, and it doesn't know of any other method that a Computer doesn't have.
You can very well send it a Desktop instead, or maybe tomorrow you will create a GamingComputer that extends Desktop or a Server class that extends Computer. You can send that as well. But showStatistics() will not have access to any of Server's specific, specialized methods, because showStatistics() doesn't know that it's looking at a Server. It wasn't even invented when showStatistics() was written.
This is consistent with the statement that even though a Server is always a Computer, a Computer is not always a Server.
You can check though. So if you know that you might be passed in a Notebook, not only a computer, you can look for that and you can even call Notebook's methods, but you have to be sure that you're looking at a Notebook:
if (computer instanceof Notebook) {
// this is definitely a Notebook, so you can assure the compiler
// of that explicitly, by using a cast
Notebook notebook = (Notebook) computer;
result += "This isn't just a generic computer, it's actually a notebook! ";
// now that you have a variable of type Notebook, you can call
// whatever Notebook provides
result += "It's produced by: " + notebook.getBrand();
}
Think of it this way, a dog is an object and a dog class might have methods such as
dog.bark()
If you cast Dog up the hierarchy to an Object, it becomes less specific.
Object o = dog;
Now all you know is that o is an object, you do not know what kind of objects and therefore you cannot know if this object can bark.
When you move UP the hierarchy you almost always lose functionality by being less specific about what you have.
The compiler needs to be told what type it should expect the object to be, so it can look up the class and see if the method is legit.
So you can say Object aThing = new Integer(25); but then you'd want to say int thingValue = (Integer)aThing.intValue();
If you have a MySubClass object that is is a subclass of MyClass, and you want to call a method defined in MyClass (even if reimplemented in MySubClass) you could say:
Object myObject = new MySubClass();
int someValue = (MyClass)myObject.methodInMyObject();
I want to use reference in Java but I don't know how!
for example in C++ we write:
void sum(int& x)
{
...
}
but in Java & sign is a compiler error!
please help me to understand references in Java.
Objects are passed by reference by default Objects are accessed by reference, but there is no way to create a reference to a primitive value (byte, short,int, long). You either have to create an object to wrap the integer or use a single element array.
public void sum(int[] i){
i[0] = ...;
}
or
public void sum(MyInt i){
i.value = ...;
}
public class MyInt{
public int value;
}
for your example something like the following could work
public int sum(int v){
return ...;
}
or
public int sum(){
return ...;
}
Update:
Additional/Better description of object references:
Java Objects are always accessed by a reference. Like the primitive types this reference is passed by value (e.g. copied). Since everything a programmer can access in java is passed by copying it (references, primitives) and there is no way to create a reference to a primitive type, any modification to a method parameter (references, primitives) only affects the local copy within the method.
Objects can be modified within a method since both copies of the reference (local and other) still point to the same object instance.
example:
Modify a primitive within method, this only affects the internal copy of i and not the passed value.
void primitive(int i){
i = 0;
}
Modify a reference within method, this only affects the internal copy of ref and not the passed value.
void reference(Object ref){
ref = new Object();//points to new Object() only within this method
}
Modify an object, visible globally
void object(List l){
l.add(new Object());//modifies the object instead of the reference
}
Both the array and MyInt above are based on the modification of an object.
An ordinary Java parameter already is closer to a C++ reference than to C++ pass-by-value or pass-by-pointer. So, all your Java methods are already like this.
int and other primitives are special in Java, however; the above is true for object references.
Edit: More precisely, as stated #fatih, all Java invocations are pass-by-value. However, when you pass an object you are passing a reference by value. So, as a first approximation, the above statement is correct: An ordinary Java parameter is more similar to a C++ reference than to C++ pass-by-value or pass-by-pointer.
Required reading on understanding Java's Pass By Value semantics:
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
http://javadude.com/articles/passbyvalue.htm
http://javachannel.net/wiki/pmwiki.php/FAQ/PassingVariables (links to several other pages)
Completely remove the notion from your head that Java can have anything passed by reference. Let's look at an example, shall we?
public class App
{
public static void main( String[] args )
{
Foo f1 = new Foo();
doSomethingToFoo(f1);
System.out.println(f1.bar); //Hey guess what, f1.bar is still 0 because JAVA IS PASS BY VALUE!!!
}
static void doSomethingToFoo(Foo f) {
f = new Foo();
f.bar = 99;
}
static class Foo {
int bar = 0;
}
}
The MutableInt class in Apache Commons will do what you want, although it's not pretty.
MutableInt
void sum(MutableInt mx)
{
int x = mx.getValue();
x = ...
mx.setValue(x);
}
...
MutableInt mx = new MutableInt(5);
sum(mx);
int result = mx.getValue();
Additional classes are provided for other primitive types, and also for objects.
There is some overhead involved in creating an additional object simply to provide a reference, so the solution is not optimal, but in most cases you should be ok.
In general, it is always best to find a way to return a result from a method. Unfortunately, Java only allows one value to be returned in this way.