我对Java泛型如何处理继承/多态性感到困惑.
假设以下层次结构 -
动物(父母)
狗 - 猫(儿童)
所以假设我有一个方法doSomething(List<Animal> animals).根据所有继承和多态的规则,我会假设a List<Dog> 是 a List<Animal>而a List<Cat> 是 a List<Animal>- 所以任何一个都可以传递给这个方法.不是这样.如果我想实现这种行为,我必须明确告诉该方法接受一个Animal的任何子类的列表doSomething(List<? extends Animal> animals).
我知道这是Java的行为.我的问题是为什么?为什么多态通常是隐含的,但是当涉及泛型时必须指定它?
我在Oracle的网站上读到了Java的类型擦除.
什么时候发生类型擦除?在编译时还是运行时?当班级加载?当类被实例化时?
很多站点(包括上面提到的官方教程)都说在编译时会发生类型擦除.如果在编译时完全删除了类型信息,那么当调用使用泛型的方法而没有类型信息或错误的类型信息时,JDK如何检查类型兼容性?
考虑以下示例:Say class A有一个方法,empty(Box<? extends Number> b).我们编译A.java并获取类文件A.class.
public class A {
public static void empty(Box<? extends Number> b) {}
}
Run Code Online (Sandbox Code Playgroud)
public class Box<T> {}
Run Code Online (Sandbox Code Playgroud)
现在我们创建另一个类B,该类empty使用非参数化参数(原始类型)调用该方法:empty(new Box()).如果我们编译B.java与A.class在类路径中,javac的是足够聪明,引发警告.所以A.class 有一些类型信息存储在其中.
public class B {
public static void invoke() {
// java: unchecked method invocation:
// method empty in class A is applied to given types
// required: Box<? extends java.lang.Number>
// found: …Run Code Online (Sandbox Code Playgroud) 是否可以创建一个使用EasyMock实现多个接口的模拟对象?
例如,界面Foo和界面Closeable?
在Rhino Mocks中,您可以在创建模拟对象时提供多个接口,但EasyMock的createMock()方法只需要一种类型.
难道possbile与EasyMock的实现这一点,而不诉诸创建扩展双方暂时接口的后退Foo和Closeable,然后嘲讽吗?
有没有办法找到泛型的类型?
if (T instanceof String) {
// do something...
}
Run Code Online (Sandbox Code Playgroud)
以上绝对不会编译.
我想知道在Java中专门化泛型类型的选项是什么,即在模板化的类中对某些类型进行特定的覆盖.
在我的例子中,我是一个泛型类(类型为T)通常返回null,但返回""(空字符串),当T是String类型时,或者当它是Integer类型时返回0(零)等.
仅提供方法的类型特定重载会产生"方法不明确"错误:
例如:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Run Code Online (Sandbox Code Playgroud)
是使用特定类型子类化泛型类的唯一选项(请参阅以下示例中的StringBar?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar …Run Code Online (Sandbox Code Playgroud) 我在我的代码中有一个场景,我想要一个类来实现两个不同类型的接口,比如这个例子:
interface Speaker<T> {
fun talk(value: T)
}
class Multilinguist : Speaker<String>, Speaker<Float> {
override fun talk(value: String) {
println("greetings")
}
override fun talk(value: Float) {
// Do something fun like transmit it along a serial port
}
}
Run Code Online (Sandbox Code Playgroud)
Kotlin对此不满意,引用:
Type parameter T of 'Speaker' has inconsistent values: kotlin.String, kotlin.Float
A supertype appears twice
Run Code Online (Sandbox Code Playgroud)
我知道一个可能的解决方案是实现以下代码,我在其中实现接口,<Any>然后自己检查类型并将它们委托给它们的函数.
interface Speaker<T> {
fun talk(value: T)
}
class Multilinguist : Speaker<Any> {
override fun talk(value: Any) {
when (value) {
is String -> …Run Code Online (Sandbox Code Playgroud) 我已经运行到Java的泛型的问题:在相同的代码编译和Java 6中正常工作,但将无法编译,因为在Java 5中同一消失的我有一个重载的方法的文件TestErasure.java ,称为"方法":
import java.util.ArrayList;
import java.util.List;
public class TestErasure {
public static Object method(List<Object> list) {
System.out.println("method(List<Object> list)");
return null;
}
public static String method(List<String> list) {
System.out.println("method(List<String> list)");
return null;
}
public static void main(String[] args) {
method(new ArrayList<Object>());
method(new ArrayList<String>());
}
}
Run Code Online (Sandbox Code Playgroud)
在Java 5中,我得到了预期的编译错误,指出"方法"的擦除是相同的:
$ javac -version
javac 1.5.0_19
$ javac TestErasure.java
TestErasure.java:10: name clash: method(java.util.List<java.lang.String>) and method(java.util.List<java.lang.Object>) have the same erasure
public static String method(List<String> list) {
^
TestErasure.java:17: method(java.util.List<java.lang.Object>) in TestErasure cannot be applied …Run Code Online (Sandbox Code Playgroud) 在使用Kotlin/Java进行编码时,我在使用强制转换和泛型时偶然发现了一些奇怪的东西.似乎有可能让类型系统认为列表是类型List<Foo>,而它实际上是一个List<Object>.
任何人都可以向我解释为什么这是可能的?
以下是Kotlin和Java中的一个例子:
Kotlin中的例子
fun <T> test(obj: Any): List<T> {
val ts = ArrayList<T>()
ts.add(obj as T)
return ts
}
fun <T> test2(obj: Any): T {
return obj as T
}
fun <T> test3(obj: Any): List<T> {
val ts = ArrayList<T>()
ts.add(test2(obj))
return ts
}
fun main(args: Array<String>) {
val x = test<Double>(1) // Returns a list of Integers and doesn't error
println(x)
val y = test2<Double>(1) // Casts the Int object to a Double.
println(y) …Run Code Online (Sandbox Code Playgroud) class A {
}
class B extends A {
}
class TestType {
public static void main(String args[]) {
A a = new B();
// I wish to use reference 'a' to check the Reference-Type which is 'A'.
}
}
Run Code Online (Sandbox Code Playgroud)
有可能吗?如果没有,那么请说明原因.
例如,我们有一些AbsractClass
package inherit;
import java.util.HashSet;
import java.util.Set;
/**
* TODO: Add comment
*
* @author Ruslan Ibragimov
*/
public abstract class AbstractClass<T extends Integer> {
private Set<String> strings = new HashSet<>();
private T value;
public Set<String> getStrings() {
return strings;
}
public void setStrings(Set<String> strings) {
this.strings = strings;
}
public void addString(String string) {
strings.add(string);
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
还有一些孩子:
package inherit;
/**
* TODO: …Run Code Online (Sandbox Code Playgroud) java ×9
generics ×8
inheritance ×2
kotlin ×2
casting ×1
easymock ×1
erasure ×1
instanceof ×1
interface ×1
jvm ×1
mocking ×1
polymorphism ×1
rhino-mocks ×1
type-erasure ×1
unit-testing ×1