In Objective-C, instancetype can be used as the return type of methods that return an instance of the class they are called on (or a subclass of that class).
What is the equivalent of instancetype in Java?
The closest to thing is to use generics
interface Base<B extends Base<B>> {
// do something and return this.
B append(String s);
}
interface SubBase<B extends SubBase<B>> extends Base<SubBase<B>> {
// append returns a SubBase<B>
}
class MyClass implements SubBase<MyClass> {
public MyClass append(String s) {
// do something
return this;
}
}
It's not so elegant, but it works.
If you mean something like this:
class Vehicle {
instancetype doNothing() {return this;}
}
class Car extends Vehicle {}
Car c = new Car().doNothing(); // no compile errors here
There is no equivalent.
One workaround that's sometimes used is to pass the type as a generic parameter:
class Vehicle<instancetype> {
instancetype doNothing() {return this;}
}
class Car extends Vehicle<Car> {}
Car c = new Car().doNothing(); // works
but then you can't use the type Vehicle without getting warnings everywhere (it has to be Vehicle<?>).
I'm no Javaist but likely there is no equivalent, because Java needs it only rarely. (And Objective-C do so, too.)
Please note that in Objective-C you do not need it most of the time, too. This is, because the compiler infers the "real" return type from the receiver, even it is declared id. This applies to -init…, +alloc…, -new…:
To determine whether a method has an inferred related result type, the first word in the camel-case selector (e.g., “init” in “initWithObjects”) is considered, and the method will have a related result type if its return type is compatible with the type of its class and if:
the first word is “alloc” or “new”, and the method is a class method, or
the first word is “autorelease”, “init”, “retain”, or “self”, and the method is an instance method.
In Java this is inferred for the new operator, too. The constructors does not have any return type, so it does not need to be inferred.
Up to here: No need for an (explicit) keyword in Java or Objective-C.
In some cases you have additional methods returning a new instance of the receivers class. Cloning/copying is such a case. In Java you have to type cast the result. In Objective-C you can use instancetype to make code easier to read. (BTW: NSObject's -copy has id as return type, not instancetype. But again usually this is no problem, because you typically assign the return value to a typed reference.)
So the short conclusion: In both Java and Objective-C the return type can be and is inferred by the compiler for most of the use cases. In rare use cases you have to explicitly cast in Java.
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.
I have class A as:
public class A {
int sayHello(int i,int j){
return i+j;
}
}
Another class B as:
public class B extends A {
#Override
int sayHello(int i, int j) {
return i+j;
}
}
If I change return type of method sayHello(int,int) of class A from int to float it shows an error because as per the overriding rule return types are also considered thats why it is not a valid overriding and overloading also.
I am confuse with why java does not allow to change returntype. why return types also needs to be same
Because:
class Parent {
int method() { return 1; }
}
class Child extends Parent {
float method() { return 1.0f; }
}
Parent p = new Child();
int myInt = p.method();
What does method() return? It should be an int, because Parent says it's an int. But Child returns an float. So what do you expect to happen? Should the JVM just crash?
By the way, you can change the return-type, but it has to be a subtype of the type, the overridden method returns. So you could override a method which returns a Parent and use Child as return-type.
You can change the return type when you override the method: it just has to be overridden with a covariant type.
For example, if you define an interface like:
interface Foo {
Object foo();
}
then it is fine to implement it thus:
class Bar implements Foo {
#Override public String foo() {
return "";
}
}
because all implementations of Foo.foo() must return an Object, and all Strings are Objects.
However, you couldn't do it the other way round: if the return type of Foo.foo() were String, you couldn't implement it to return an Object, because callers of the method need to be able to invoke String's methods on that instance. For instance:
void test(Foo instance) {
System.out.println(instance.foo().length());
}
This wouldn't work at runtime if an Object were returned, as there is no length() method on an Object. (But more specifically, it must be the String.length() method, not just any length method: Java does not support duck typing). The compiler can detect this mismatch, and so it stops you doing it.
There are no types covariant with int (or any primitive type, for that matter), so you have to return an int when you override a method which returns int.
The theoretical reason why this is allowable is the Liskov Substitution Principle, which can be paraphrased as "subtype methods can be more general in the parameters they accept, and more specific in the types they return".
Java doesn't allow more general parameter types to be used, however, because of the way it resolves method overloads.
As illustrated here (emphasis my own)
The ability of a subclass to override a method allows a class to
inherit from a superclass whose behavior is "close enough" and then to
modify behavior as needed. The overriding method has the same name,
number and type of parameters, and return type as the method that it
overrides. An overriding method can also return a subtype of the type
returned by the overridden method. This subtype is called a covariant
return type.
If the return type is not the same, it will break things for other classes which could use polymorphism to detect the type of the class at runtime.
Basically, Java considers this (very correctly, I think ...) to be a nasty-bug(!) that it just helpfully caught for you at compile time.
The essential idea behind descendent-classes and overrides is that callers need not be concerned as to which “flavor” of a particular class-instance they might be dealing with, as long as it is known that it is an instance of that class or one of its descendants. The compiler can also generate reliable code, because although the underlying implementation of a particular class might vary, the prototype does not: each instance will have the same methods, a-n-d, will return the same data types.
If you need to special-case return a different data type, you should define a custom method to do so. This will also(!) be important for the various Programmers Who Will Follow You. (“Too bad about that bread-truck ...” etc.) If your code does something different, it should very-noticeably look different in the application source-code!
Remember: if Java actually allowed you to do this sort of thing, you might unwittingly introduce nas-s-s-s-ssty bugs in any piece of existing, “debugged,” code, anywhere(!) in your undoubtedly-vast application, that happened to stumble-upon an instance of “your special-case.”
I have this little problem and I want to find out whay is this happening to me:
I made class like this:
public class SomeSimpleClass {
//and I had method who returns generic. it can be instance of whatever, and for sure can be casted to U:
public <U>U giveMeSomething(String arg) {
return (U)SomewhereSomething.getValueCastingIsOK(arg);
}
}
and then I am using it like this:
// give me some number:
Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");
OR
String text = instanceSomeSimpleClass.giveMeSomething("I want text now");
and everything is ok. getValueCastingIsOK from SomewhereSomething returns me what I want, and I dont need type cast on the giveMeSomething. Looks like the U is replaced by the type from the associative variable.. and everything is cool..
BUT then I create a new class:
public class SomeOtherClass <T extends Something> {
//And I have the exactly same method here:
public <U>U giveMeSomething(String arg) {
return (U)SomewhereSomething.getValueCastingIsOK(arg);
}
}
and now when I want to use it in the same way, the compiler (I am using Java 1.7) is telling me, that I have to use typecast, and start to using the giveMeSomething like this, because U is now the Object, and nothing else...
Integer number = (Integer)instanceSomeSimpleClass.giveMeSomething("I want integer value");
:(
Why in the second case the compiler cant get the U type in the same way, as in the first case. And what I have to do, to be that this way?
Thank for an answers, suggestions.. ;)
The problem is that you're using a raw type of the class SomeOtherClass, but not supplying any type parameters to your declaration:
SomeOtherClass instanceSomeSimpleClass = new SomeOtherClass();
When you do this, the Java compiler will replace ALL generics in the class with the type erasure version, even unrelated generics such as your generic method. The type erasure of the method
public <U>U giveMeSomething(String arg) {
becomes
public Object giveMeSomething(String arg) {
which requires the cast to Integer.
You must either supply a type parameter to SomeOtherClass (useless, unless you've eliminated unnecessary code that uses T to post the class code here):
SomeOtherClass<Something> instanceSomeSimpleClass = new SomeOtherClass<Something>();
Or you can remove the type parameter on the class definition, as you had it originally:
public class SomeSimpleClass {
Either will keep the generic method intact and eliminate the need to cast the return type of giveMeSomething.
You're missing the java syntax for explicit typing:
public <U>U giveMeSomething(String arg) {
return SomewhereSomething.<U>getValueCastingIsOK(arg);
}
Notice the <U> between the dot and the method name. Notice also that casting is now not required.
That's how you explicitly declare what the type is for a typed method. Without this, java must infer the type, which it can't here, so (unsafe) casting is required.
Another example to illustrate. In this case, java can infer the type is Integer because of the type that the result is being assigned to:
Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");
But if you were to use the value without assigning it, you'd need to pass to type:
someIntegerRequired(instanceSomeSimpleClass.<Integer>giveMeSomething("I want integer value"));
I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?
You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)
The Function type is declared as
interface Function<T,R> {
R apply(T t);
}
However, the Consumer type is compatible with that you are looking for:
interface Consumer<T> {
void accept(T t);
}
As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.
For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:
List<String> allJedi = asList("Luke","Obiwan","Quigon");
allJedi.forEach( jedi -> System.out.println(jedi) );
You can see above that in this case, the lambda expression receives a parameter and has no return value.
Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.
I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:
Consumer<String> block = System.out::println
Or I could simply do
allJedi.forEach(System.out::println);
The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.
So, in your code, you need to change your method signature to somewhat like:
public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) {
list.forEach(myBlock);
}
And then you should be able to create a consumer, using a static method reference, in your case by doing:
myForEach(theList, Test::displayInt);
Ultimately, you could even get rid of your myForEach method altogether and simply do:
theList.forEach(Test::displayInt);
About Functions as First Class Citizens
All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.
When you need to accept a function as argument which takes no arguments and returns no result (void), in my opinion it is still best to have something like
public interface Thunk { void apply(); }
somewhere in your code. In my functional programming courses the word 'thunk' was used to describe such functions. Why it isn't in java.util.function is beyond my comprehension.
In other cases I find that even when java.util.function does have something that matches the signature I want - it still doesn't always feel right when the naming of the interface doesn't match the use of the function in my code. I guess it's a similar point that is made elsewhere here regarding 'Runnable' - which is a term associated with the Thread class - so while it may have he signature I need, it is still likely to confuse the reader.
Set return type to Void instead of void and return null
// Modify existing method
public static Void displayInt(Integer i) {
System.out.println(i);
return null;
}
OR
// Or use Lambda
myForEach(theList, i -> {System.out.println(i);return null;});
why following code doesn't compile ?
class aa1 <String> {
public void fun(){
String s = ""; // not compiling
}
}
class aa2 <String> {
String s = ""; // not compiling
}
class aa3 <String> {
String s = (String)""; // compiling
}
can some tell or give me link for this
thanks.
I think you may have misconstrued the idea behind generics. The point is that your class (aa, in this case) can be... well, generic. It's not of one fixed type, but rather can be any number of types through polymorphism. The generic type is similar to a variable name, but it represents a class, rather than an instance of a class. You could do something like:
class aa <T> {
public void fun(T myObject){
T s = myObject;
}
}
This is an appropriate use of generics. T just represents "some class". The reason the example you posted didn't compile because you overrode the visibility of String (making it the generic type, rather than java.lang.String). If you don't want it to be any class, but some subset of classes, you can do something like:
class aa <T extends MyInterface> {
public void fun(T myObject){
T s = myObject;
}
}
In this case, you're guaranteed that instances of class T also extend the interface MyInterface. However, you cannot extend String, since it's final. If all you wanted was for the String object to be set, you do not need generics at all:
class aa {
public void fun(){
String s = "";
}
}
For more information about generics, read over the Java tutorials on generics.
The generic parameter "String" hides the java.lang.String in this case.
in the class, if you declare the string s and specify its data type as "java.lang.String" then compiler won't complain.
public class aa<String> {
java.lang.String s = "" ;
}
Your code makes no sense - the declaration makes no sense - what are you really trying to do here?
The reason you're having issues compiling is that you're making a generics declaration that's hiding the JDK's java.lang.String.
You're also declaring the same class 3 times. Something like this would compile, but still probably doesn't achieve what you want.
class aa<NotString> {
public void fun() {
String s = ""; // compiles
}
}
class aa2<NotString> {
String s = ""; // compiles
}
class aa3<NotString> {
String s = (String) ""; // compiling
}
Well, it seems that your generic parameter name (String) hides the java.lang.String type.
I would recommend renaming your generic parameter. By the way, which type do you want your s to be: java.lang.String or the same as the parameter? In the latter case, how cuold the compiler assign "" (which is of type java.lang.String) to the potentially irrelevant type represented by the generic parameter?
In your example you are declaring String as an identifier. You must not use keywords or type names. (Generics Tutorial).
Since you're declaring the generic type String, that will override the default java.lang.String type, your code is like typing:
class aa<T> {
T s = "";
}
T is simply Object after type erasure, but since it can be initialized with anything (for example Integer), the compiler won't let you assign Strings to it.