我正在学习Java中的泛型,我接近了一段非常有趣的代码.我知道在Java中将一种类型的列表添加到另一种类型是违法的.
List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList=integerList;
Run Code Online (Sandbox Code Playgroud)
所以在第二行我得到一个编译时错误.
但是如果我在这样的类中创建一个泛型方法,
class GenericClass <E>{
void genericFunction(List<String> stringList) {
stringList.add("foo");
}
// some other code
}
Run Code Online (Sandbox Code Playgroud)
并且在主类中调用带有Integer列表的方法我没有收到任何错误.
public class Main {
public static void main(String args[]) {
GenericClass genericClass=new GenericClass();
List<Integer> integerList= new ArrayList<Integer>();
integerList.add(100);
genericClass.genericFunction(integerList);
System.out.println(integerList.get(0));
System.out.println(integerList.get(1));
}
}
Run Code Online (Sandbox Code Playgroud)
输出
100
foo
为什么我没有收到任何错误?
我有一个抽象类,它有一个泛型方法,我想通过用特定类型替换泛型参数来覆盖泛型方法.所以在伪代码中我有以下内容:
public abstract class GetAndParse {
public SomeClass var;
public abstract <T extends AnotherClass> void getAndParse(T... args);
}
public class Implementor extends GetAndParse {
// some field declarations
// some method declarations
@Override
public <SpecificClass> void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Run Code Online (Sandbox Code Playgroud)
但由于某种原因,我不允许这样做?我是在做某种语法错误还是这种继承和覆盖是不允许的?具体来说,我收到一个错误,@Override
因为eclipse IDE一直在提醒我实现getAndParse
.
以下是我希望上述代码的工作方式.我的代码中的其他地方有一个方法,它需要实现的对象实例,GetAndParse
这意味着它们有一个getAndParse
我可以使用的方法.当我调用getAndParse
该实例时,编译器会检查我是否T
以正确的方式使用了特定的实例,因此特别T
应该扩展AnotherClass
它应该是SpecificClass
.
为什么以下代码编译?该方法IElement.getX(String)
返回该类型IElement
或其子类的实例.类中的代码Main
调用该getX(String)
方法.编译器允许将返回值存储到类型的变量中Integer
(显然不在层次结构中IElement
).
public interface IElement extends CharSequence {
<T extends IElement> T getX(String value);
}
public class Main {
public void example(IElement element) {
Integer x = element.getX("x");
}
}
Run Code Online (Sandbox Code Playgroud)
返回类型是否仍然是一个实例IElement
- 即使在类型擦除之后?
该getX(String)
方法的字节码是:
public abstract <T extends IElement> T getX(java.lang.String);
flags: ACC_PUBLIC, ACC_ABSTRACT
Signature: #7 // <T::LIElement;>(Ljava/lang/String;)TT;
Run Code Online (Sandbox Code Playgroud)
编辑:替换String
与一致Integer
.
如果在Java中创建泛型类(该类具有泛型类型参数),您可以使用泛型方法(该方法采用泛型类型参数)吗?
请考虑以下示例:
public class MyClass {
public <K> K doSomething(K k){
return k;
}
}
public class MyGenericClass<T> {
public <K> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所期望的泛型方法,我可以调用任何对象的doSomething(K)
实例MyClass
:
MyClass clazz = new MyClass();
String string = clazz.doSomething("String");
Integer integer = clazz.doSomething(1);
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试使用MyGenericClass
没有指定泛型类型的实例,我调用doSomething(K)
返回一个Object
,无论K
传入什么:
MyGenericClass untyped = new MyGenericClass();
// this doesn't compile - "Incompatible types. Required: String, Found: Object" …
Run Code Online (Sandbox Code Playgroud) C++不支持虚拟模板方法.原因在于,vtable
无论何时进行这种方法的新实例化(必须将其添加到vtable
),这都会改变.
相比之下,Java确实允许虚拟通用方法.在这里,还清楚如何实现:Java泛型在运行时被擦除,因此泛型方法是运行时的常用方法,因此不需要对其进行更改vtable
.
但现在到C#.C#确实有具体的泛型.使用具体化的泛型,特别是当使用值类型作为类型参数时,必须有不同版本的泛型方法.但是后来我们遇到了与C++相同的问题:每当进行泛型方法的新实例化时,我们都需要改变vtable.
我对C#的内部工作并不是太深入,所以我的直觉可能完全是错误的.那些对C#/ .NET有更深入了解的人能告诉我他们如何在C#中实现通用虚拟方法吗?
这是代码,以显示我的意思:
[MethodImpl(MethodImplOptions.NoInlining)]
static void Test_GenericVCall()
{
var b = GetA();
b.M<string>();
b.M<int>();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static A GetA()
{
return new B();
}
class A
{
public virtual void M<T>()
{
}
}
class B : A
{
public override void M<T>()
{
base.M<T>();
Console.WriteLine(typeof(T).Name);
}
}
Run Code Online (Sandbox Code Playgroud)
在调用M
函数时,CLR如何调度到正确的JITed代码Test_GenericVCall
?
这是一个问题,第一个代码清单编译得很好(JDK 1.6 | JDK 1.7):
ArrayList<String> a = new ArrayList<String>();
String[] s = a.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)
但是,如果我将List
引用声明为原始类型:
ArrayList a = new ArrayList();
String[] s = a.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)
我收到编译器错误,说明String[]
是必需的,但是Object[]
找到了.
这意味着我的编译器将泛型方法解释为返回,Object[]
尽管String[]
它接收了一个as参数.
我加倍检查了toArray(myArray)
方法签名:
<T> T[] toArray(T[] a);
Run Code Online (Sandbox Code Playgroud)
因此,它是一个参数化方法,其类型参数<T>
与List(即<E>
)的类型参数无关.
我不知道在这里使用原始类型如何影响使用独立类型参数的参数化方法的评估.
我正在研究Java通用功能,我不知道如何解释以下main
方法中的第三行:
public class Example4 {
public static void main(final String[] args) {
System.out.println(Util.<String>compare("a", "b"));
System.out.println(Util.<String>compare(new String(""), new Long(1)));
System.out.println(Util.compare(new String(""), new Long(1)));
}
}
class Util {
public static <T> boolean compare(T t1, T t2) {
return t1.equals(t2);
}
}
Run Code Online (Sandbox Code Playgroud)
第一行编译,运行和返回(如预期的那样)false
.
第二行没有按预期编译,因为我明确地混合String
和Long
.
第三行编译,运行并返回false但我不确定它是如何工作的:编译器/ JVM是否将参数类型实例T
化为Object
?(另外,有没有办法获得这个声明类型的T
运行时?)
谢谢.
我有一个抽象类:
abstract class Foo(...){
def bar1(f : Foo) : Boolean
def bar2(f : Foo) : Foo
}
Run Code Online (Sandbox Code Playgroud)
多个类扩展Foo并覆盖方法
class FooImpl(...) extends Foo{
override def bar1(f : Foo) : Boolean {
...
}
override def bar2(f : Foo) : Foo {
...
}
}
Run Code Online (Sandbox Code Playgroud)
有可能,使用泛型(或其他东西)使重写方法具有实现它的子类的参数类型吗?像这样 :
class FooImpl(...) extends Foo{
override def bar1(f : FooImpl) : Boolean {
...
}
override def bar2(f : FooImpl) : FooImpl {
...
}
}
Run Code Online (Sandbox Code Playgroud)
我正在思考下面的内容,但这似乎不起作用......
abstract class Foo(...){
def bar1[T <: Foo](f : T) …
Run Code Online (Sandbox Code Playgroud) 我无法理解下面两个代码片段之间的区别.有人可以帮我解释一下吗?
首先,我必须说我有很多类扩展了一个名为的超类BaseEntity
,那么以下片段的区别,优点和缺点是什么?
// 1
public <T extends BaseEntity> T getName(T t) {
return t;
}
// 2
public BaseEntity getName(BaseEntity t) {
return t;
}
Run Code Online (Sandbox Code Playgroud) 好了,所以我在一个Java的人开始使用C#和我的编码,并开始做一个通用的方法和我写的运行和编译,但它违背我知道一切泛型应该如何工作的,所以我希望有人能解释这个对我来说:
所以我有一个通用的方法定义如下:
public static List<T> CopyAsList<T>(IEnumerable<T> list, Object lockObject)
{
if (list != null)
{
lock (lockObject)
{
return new List<T>(list);
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
但对我来说奇怪的是我可以在没有指定的情况下调用这个泛型方法T
,它会起作用:
List<String> strings = new List<string>() { "a", "b", "c"};
List<int> ints = new List<int>() { 1,2,3};
object lockObject = new object();
foreach (string s in CopyAsList(strings, lockObject))
{
Console.WriteLine(s);
}
foreach (int i in CopyAsList(ints, lockObject))
{
Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)
如何在没有指定泛型类型的情况下编译代码?C#是否在运行时推断出类型?
generic-method ×10
generics ×8
java ×7
c# ×2
overriding ×2
raw-types ×2
.net ×1
.net-3.5 ×1
c++ ×1
inheritance ×1
methods ×1
scala ×1
templates ×1
type-erasure ×1
typesafe ×1