class MyClass {
private String str;
public MyClass(String str){
this.str = str;
}
public int compare(Object o) {
return str.compareTo(((MyClass)o).str); //line No.8
}
}
class Client {
public static void main(String[] args) {
MyClass m = new MyClass("abc");
MyClass n = new MyClass("bcd");
System.out.println(m.compare(n));
}
}
Why in this snippet of code the cast (MyClass)o in line number 8 is necessary, despite the fact that the Client invokes a compare method with arguments which are instances of MyClass class?
When I modify the compare method in MyClass class to form like below:
public int compare(Object o) {
System.out.println(o.getClass());
System.out.println(((MyClass)o).getClass());
return str.compareTo(((MyClass)o).str);
}
Then, the Client will produce the following result:
class MyClass
class MyClass
Thus I don't understand why the cast above is required and why I can't just do like that (without cast to MyClass):
public int compare(Object o) {
return str.compareTo(o.str);
}
Because when I do that, I get the compile time error:
str cannot be resolved or is not a field
This comes down to what the compiler knows at compile time. At compile time it knows that what is going to be passed into this method is of type Object. That means that it can guarantee the methods that are associated with the class Object, but not the methods of type MyClass.
Because that compare method takes any argument of type Object, or a subclass, you could pass anything in. What if I make a class MyOtherClass like this..
public class MyOtherClass {
public String notStr;
}
And I do something like..
MyOtherClass myOtherClass = new MyOtherClass();
MyClass myClass = new MyClass();
myClass.compare(myOtherClass);
Without the cast, you've now got a situation where at runtime, it attempts to access a field that is not there. The cast is put in place to guarantee that the object is of the correct type, or it will fail before it attempts to access that field.
Just as an Aside
I've been working extensively with a language called Groovy. It is a language that essentially sits on top of Java, but it supports things like dynamic binding and loose typing (which is what you're after here). If this kind of functionality is a must have for you, then I would recommend checking out the documentation.
o's type in compare is an Object. This means the parameter it could be a MyClass instance, but it also could not. Object doesn't have any field called str (as that one belongs to MyClass), so there's no way to get that field from it, and so the code can't compile. If you cast to MyClass, however, it will have a field called str, and so it will be able to access it.
Related
I have different objects(Object A and object B). But some of the objects' fields are same. I can't change the object classes( i mean i cant write a implement/extends condition for them). I want to pass the objects to a method which uses the objects' fields They have same fields. I don't want to overloading. Which design is the most suitable for this?.
A obj1 = new A();
B obj2 = new B();
update(obj1);
update(obj2);
// my function
public <T extends myInterface> void update(T obj)
{
obj.field+=1;
}
public interface myInterface{
int field=0;
}
--------------
public class A{
int field;
.... // smt else
}
--------------
public class B{
int field;
.... // smt else
}
If you have two classes which do not implement a common interface or share a common base class, you can't really pass them to your function.
The fact that they have a common field doesn't matter.
You have 3 workarounds, none of which is really good:
Have your function accept Object type, and check its type (A or B) inside using instanceof. This is ugly and not recommended as any class can be passed inside, and also your code has to check it's type all the time.
Have your function accept Object type, Use reflection to access field with specific name, in this way:
Field field = obj.getClass().getDeclaredField('myfeild');
Object value = field.get(obj);
This is better in that your code doesn't have to check types, but more unsafe. Any class can be passed to your function, and there's some dark magic which relies on static field names. If field name changes, your code breaks.
Perhaps the best - Implement a wrapper for your objects. It will have two constructors, one for class A and one for class B. The wrapper will remember which kind of object resides inside. In its getField function if will have a single if statement. Have your function accept the wrapper type as the argument.
instanceof can be used indentify class of object. Like this:
public <T extends myInterface> void update(Object obj)
{
if ( obj instanceof A )
{
A a = (A)obj;
a.field+=1;
}
if( obj instanceof B )
{
B b = (B)obj;
b.field+=1;
}
}
Suppose I have the following method:-
public static void abhay(Object a){
....
}
and I use it somewhere like this:-
public static void main(String[] args){
...
Kaal b = new Kaal();
abhay(b);
...
}
where Kaal is a class, obviously.
Now, what will be the class type(object type at compile time) of a inside the method abhay? In other words, what will be the class of a, in the eyes of compiler, when inside method abhay?
Also, how above is different than below?
(given that we only change the definition of abhay):-
public static void abhay(Kaal a){
....
}
"Java is always 'call by value'. Instead of the object, only the reference to the object, is passed as an argument, where this reference, is, the value."
If the above fact has any relevance to the answer to this question, please try to explain in context of above fact.
The compiler only cares about the signature of the method it is currently in.
It can't know and doesn't care about how that method is invoked.
So, to the compiler sees that abhay() has declared a to be an Object; and that is what the compiler knows about a.
Of course, at runtime, a call like b instanceof Kaal will result to true.
And just for the record: this has nothing to do with call-by-value or call-by-reference.
The answer is straight forward. Given the following method signature:
public static void abhay(Object a)
and you invoke it by abhay(new Kaal());
It is like saying:
Object a = new Kaal(); //only able to access members of Object
Because you told Java to handle it as an Object, it will be treated as an Object. To access members of Kaal:
((Kaal)a).kaalMethod();
This is just a matter of Java complying to the data type given in the parameter list. It has nothing to do with "pass by value". Further more, both instances Kaal and Object are objects. You are not even dealing with primitives here where the value are referring to the actual content of the primitives.
Take Kaal as a parameter and you can access Kaal methods
public static void abhay(Kaal a){
a.getSomeKaalMethod(); // works
....
}
Take Object as a parameter, and pass a Kaal class, and you can't access Kaal methods or fields
public static void abhay(Object a){
a.getSomeKaalMethod(); // doesnt work
....
}
Unless you cast the object to Kaal
public static void abhay(Object a){
Kaal k = (Kaal)a;
k.getSomeKaalMethod(); // works
....
}
You might want to check if is instanceof Kaal other wise I dont see why you will take a Object instead of the class
public static void abhay(Object a){
if(a instanceof Kaal){
Kaal k = (Kaal)a;
k.getSomeKaalMethod(); // works
}
}
I have this class, just for the purpose of learning:
public class MyClass{ //Looking for a solution without making my class also generic <Type>
//Private Arraylist var to hold the value called myvar
public MyClass(ArrayList<MyDesiredType> incoming) {
//CODE myVar=incoming
}
public MyDesiredType getType() {
return myVar.get(0);
}
}
Is there any way to infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness, but most of all WITHOUT making the whole class GENERIC (seems redundant to me)? If not, why should I think this is not feasible for the compiler?
This is a reformulated question I already did, but it was my first one and I learned how to expose it clear because nobody understood. I tried to edit later the original question but everything was buried. I changed and simplified the example and try to put it easy. Original question: Java Generics Silly Thing (Why cant I infer the type?).
If there is any problem just tell it to me and I will remove it.
No, there is not. How would the compiler know what type to return? The generic type of ArrayList in the constructor will not be known during compile time. You either have to make the whole class generic or take another approach.
Consider this:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(arrList);
String testStr = test.returnWhat();
System.out.println("testStr");
}
private final List myList; //warning
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat() {
return (T) myList.get(0); //warning
}
}
This works but gives you warnings on the marked lines. So, really there is no way to achieve what you are describing without making the whole class generic.
Because, what if:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(); // now what?
String testStr = test.returnWhat(0); // no warning...
JPanel p = test.returnWhat(0); // goes through without warning, real nice...
test.returnWhat(0); // returns Object
Test test2 = new Test(arrList);
test2.addElement(new Object()); // boom, inserted object into list of string.
String nono = test2.returnWhat(1); // the universe goes down. assign an object to string without warning. even
// though one COULD think the class is generic.
}
// private List<T> myList = new ArrayList<T>(); compiler error, T is unknown
private List myList = new ArrayList();
public Test() {
myList.add(new Object());
}
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat(int index) {
return (T) myList.get(index);
}
public <T> void addElement(T el) {
myList.add(el);
}
}
The second one doesn't compile when myList is made generic. How could the compiler determine the type of <T> in the case where the default constructor is used?
Further, this could lead to serious problems with Objects in collections that rely on the fact that only certain types are inserted.
This will generate the following exception:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String at
Test.main(Test.java:27)
Did I manage to convince you?
Real nice question, btw. I had to think about this one quite a bit.
When you say that you want the compiler to "infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness", it seems that you are saying that it should infer the result of getType() from the input of the constructor. If both happen in the same function, it could. The problem is that the object may not exist in only one function, and so the extra type information (the generic type) is needed to pass this kind of object between functions.
For example, if I want to write a function that takes a MyClass object, I need to know what getType() will return so I can use the returned value. By adding a generic type of MyClass we are giving a description to what it holds.
Another way to look at it is that MyClass is a container. By adding generics, we are saying it is a container of a specific type of thing, and so we can more easily predict what we will get out of it.
There is no way for the compiler to know at runtime what type your arraylist is. I really dont see the problem using something along the lines of this:
public class MyClass<TYPE> {
private ArrayList<TYPE> incoming;
public MyClass(ArrayList<TYPE> incoming) {
this.incoming = incoming;
}
public TYPE getType() {
return incoming.get(0);
}
}
This way you can do:
ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();
Or am i misinterpreting the question and you want to know the class at runtime?
No, if you want a class that can hold a list of a parameterized type.
Yes, if you want a class that can hold a list of exactly one type. You can declare that type explicitly in the field, constructor and accessor.
What you're forgetting is that not all code that you may run against is visible to the compiler! Jars can be added, removed, substituted at run time, that the compiler never saw. You may compile against an interface that is just:
public interface MyClassFactory {
MyClass getInstance();
}
Then at runtime you supply into the JVM an implementation. So the compiler never saw the actual code creating the MyClass that you will be using, so there is no way to perform such a compile time inference. You must either make the class generic or accept that there will not be type safety.
I was wondering what is the difference between the following two method declarations:
public Object doSomething(Object obj) {....}
public <T> T doSomething(T t) {....}
Is there something you can/would do with one but not the other? I could not find this question elsewhere on this site.
Isolated from context - no difference. On both t and obj you can invoke only the methods of Object.
But with context - if you have a generic class:
MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();
Then:
Foo newFoo = my.doSomething(foo);
Same code with object
Foo newFoo = (Foo) my.doSomething(foo);
Two advantages:
no need of casting (the compiler hides this from you)
compile time safety that works. If the Object version is used, you won't be sure that the method always returns Foo. If it returns Bar, you'll have a ClassCastException, at runtime.
The difference here is that in the first, we specify that the caller must pass an Object instance (any class), and it will get back another Object (any class, not necessarily of the same type).
In the second, the type returned will be the same type as that given when the class was defined.
Example ex = new Example<Integer>();
Here we specify what type T will be which allows us to enforce more constraints on a class or method. For example we can instantiate a LinkedList<Integer> or LinkedList<Example> and we know that when we call one of these methods, we'll get back an Integer or Example instance.
The main goal here is that the calling code can specify what type of objects a class will operate upon, instead of relying on type-casting to enforce this.
See Java Generics* from Oracle.
*Updated Link.
The difference is that with generic methods I don't need to cast and I get a compilation error when I do wrong:
public class App {
public static void main(String[] args) {
String s = process("vv");
String b = process(new Object()); // Compilation error
}
public static <T> T process(T val) {
return val;
}
}
Using object I always need to cast and I don't get any errors when I do wrong:
public class App {
public static void main(String[] args) {
String s = (String)process("vv");
String b = (String)process(new Object());
}
public static Object process(Object val) {
return val;
}
}
You don't need to do additional class casting. In first case you will always get an object of class java.lang.Object which you will need to cast to your class. In second case T will be replaced with the class defined in generic signature and no class casting will be needed.
At runtime, nothing. But at compile time the second will do type checking to make sure the type of the parameter and the type of the return value match (or are subtypes of) whatever type T resolves to (the first example also does type checking but every object is a subtype of Object so every type will be accepted).
T is a generic type. Meaning it can be substituted by any qualifying object at runtime. You may invoke such a method as follows:
String response = doSomething("hello world");
OR
MyObject response = doSomething(new MyObject());
OR
Integer response = doSomething(31);
As you can see, there is polymorphism here.
But if it is declared to return Object, you can't do this unless you type cast things.
in the first case it takes a parameter of any type e.g.string and return a type foo. In the second case it takes a parameter of type foo and returns an object of type foo.
There are few reasons that you can consider Generics over Object type in Java:
Generics is flexible and safe. At the same time, working with Object that requires type-casting is error-prone
Type Casting in Java is slow
ref : [1]: https://www.infoworld.com/article/2076555/java-performance-programming--part-2--the-cost-of-casting.html
How do I create a reference to a constant object?
final Myclass obj = new Myclass();
does not work, it says obj(the reference) should not be re-assigned but we can still change the object referred. I want to ensure that the object itself does not change once constructed.
Just make it immutable (like String is). Or wrap it in another object which restricts access to mutators of the object in question (like Collections.unmodifiableList() and consorts do).
You are mixing two things: final and immutable.
A variable can be final, so you can't change it's a value (or object reference) after it is initialized (but of course you can change the reference's objects attributes)
An object can be immutable (not a keyword but a property), so you can't change it's value after it is created. The string is a good example - you can not change the backing char[] inside a String object.
What you want is an Immutable Object. There are no keywords in Java that can instantly make an object immutable. You have to design the object's logic, so that its state cannot be changed. As BalusC put, you can wrap it in another object which restricts access to its mutators.
I don't think there's any built in keyword to make that possible in Java. Even if the reference is constant/final, the internals of the object could still be changed.
Your best options is to have a ReadOnly implementation version of your class.
You can read more about this here: http://en.wikipedia.org/wiki/Const-correctness#final_in_Java
In Java, an immutable class is generally means that it doesn't have "setters" and any field that can be accessed with a "getter" should also be immutable. In order to get your data into the class to start, you'll need to have a constructor that takes the values as arguments:
public class MyClass {
String something;
int somethingElse;
// The class can only be modified by the constructor
public MyClass(String something, int somethingElse) {
this.something = something;
this.somethingElse = somethingElse;
}
// Access "something". Note that it is a String, which is immutable.
public String getSomething() {
return something;
}
// Access "somethingElse". Note that it is an int, which is immutable.
public int getSomethingElse() {
return somethingElse;
}
}
Yes it does you seem to have forgotten to set the type.
final MyClass obj = new Myclass();
That means that obj can only be assigned once. Java does not have a const keyword like C++ does. If MyClass is not declared final (final class MyClass { ... }) it can still change.
final variables should be assigned in the moment of declaration.
final MyClass obj = new MyClass();
In java object constant means you cannot change its reference but you can change the values of its state variables untill they are not final. if all the member variables are final then its a perfect constant, where you cannot change anything.
Here is a way to wrap any object to make it "roughly" immutable.
All method calls that are not 'getters' will throw an Exception. This code defines a getter as a method that meets these criteria:
name of the method starts with get or is
it takes no arguments
it returns a value (not void return type)
Yes, getter methods could mutate an object. But if your code (or code you are using) is doing that, you have some bigger problems, please go get some help :)
the code:
class ImmutableWrapper
public static <T> T wrap(T thing) {
return (T) Proxy.newProxyInstance(thing.getClass().getClassLoader(), new Class[]{thing.getClass()}, OnlyGettersInvocationHandler.instance);
}
private static class OnlyGettersInvocationHandler implements InvocationHandler {
public static InvocationHandler instance;
#Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String name = method.getName();
if ((args == null || args.length == 0)
&& (name.startsWith("get") || name.startsWith("is")
&& !method.getReturnType().equals(Void.class))) {
return method.invoke(proxy, args);
} else {
throw new UnsupportedOperationException("immutable object: " + proxy + ", cannot call " + name);
}
}
}
}
SomeClass myThing = ... create and populate some object ...
SomeClass myImmutableThing = ImmutableWrapper.wrap(myThing);
myImmutableThing.setValue('foo'); // throws Exception
myImmutableThing.whatever(); // throws Exception
myImmutableThing.getSomething(); // returns something
myImmutableThing.isHappy(); // returns something
Mayby you can create class with final attributes. So, you can't change it: object == const.
At least "String" immutable because of it:
public final class String implements Serializable, Comparable<String>, CharSequence {
private final char[] value;
//...
}