为什么我不能将原始类型分配给参数化类型? (JAVA) [英] Why can't I assign a Raw Type to a Parameterized Type? (Java)

查看:432
本文介绍了为什么我不能将原始类型分配给参数化类型? (JAVA)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果将一个参数化类型对象分配给一个原始类型对象,据我所知,原始类型对象采用参数化类型。这对我有意义。但为什么它不能以其他方式工作?我认为将Raw Type分配给Paramterized Type之后,编译器会简单地假设参数化类型。



感谢您的帮助!



好吧,据我了解,以下方法不会出现问题,将Raw Type当作String类型传递:

  SomeClass的<字符串> instance1 = new SomeClass<>(); 
SomeClass instance2 = instance1;

但是,以下内容会引发警告,并且任何类中都不会隐含一种类型的字符串方法:

  SomeClass instance1 = new SomeClass(); 
SomeClass< String> instance2 = instance1;

不过,我想我已经知道了,但如果真是这样,我很抱歉浪费大家的时间。这是否工作,因为instance2是创建一个指针,而不是一个新的对象,并且一个指针不能改变它指向的对象的行为?

解决方案

泛型只有编译时间。基本上,当代码被编译时,参数化类型会被擦除并被替换为类型转换。



考虑类似下面的内容:

  class SomeClass< T> {
T值;

T get(){
返回值;
}

void set(T val){
value = val;


当你声明一个新的SomeClass时,它看起来像是发生了什么是这样的:

  class SomeClass {
字符串值; //value is now a String

String get(){
return value;
}

void set(String val){
value = val;
}
}

但实际情况并非如此。实际情况是SomeClass总是这样:

  class SomeClass {
Object value; //擦除T是Object

Object get(){
返回值;
}

void set(Object val){
value = val;
}
}

当你有一个 SomeClass< String> ,无论何时说 String someString = someClass.get(); ,编译器都会将Object强制转换为String。在运行时,原始时间和参数化类型之间没有行为差异,只有是否存在转换。这就是为什么原始类型是不好的原因,因为原始类型和不使用泛型之间基本上没有区别。

试试这个:

  SomeClass< String> pam = new SomeClass< String>(); 

((SomeClass)pam).set(new Integer(0));

System.out.println(((SomeClass)pam).get()); //打印0
System.out.println(pam.get()); // ClassCastException

所以要清楚的是,当您这样做时:

  SomeClass< String> instance1 = new SomeClass<>(); 
SomeClass instance2 = instance1;

没有类型是通过的。 instance2 不是 SomeClass< String>



当你这样做时:

  SomeClass instance1 = new SomeClass(); 
SomeClass< String> instance2 = instance1;

由于不安全,您会收到警告。不能保证 instance1 的值是一个字符串,但是如果你调用get instance2



给出以下代码片段:

  SomeClass< String> instance1 = new SomeClass< String>(); 
SomeClass instance2 = instance1;

System.out.println(instance1.get());
System.out.println(instance2.get());

print语句编译为以下字节码:

  getstatic PrintStream System.out 
aload_1 instance1
invokevirtual Object SomeClass.get()// instance1.get()返回Object
checkcast字符串/ /它被转换为字符串
invokevirtual void PrintStream.println(String)//为字符串$ b $调用println getstatic PrintStream System.out
aload_2 instance2
invokevirtual Object SomeClass.get() // instance2.get()返回Object
invokevirtual void PrintStream.println(Object)//调用println for Object

正如你所看到的,除了演员之外没有任何区别。


If one assigns a Parameterized Type Object to a Raw Type Object, as I understand it the Raw Type Object assumed the Parameterized Type. This makes sense to me. But why can't it work the other way around? I would think that after assigning a Raw Type to a Paramterized Type, the compiler would simply assume the Parameterized type.

Thanks for any help!

Alright, as I understand it, the following will work no problem, treating the Raw Type as if a String type were passed:

SomeClass<String> instance1 = new SomeClass<>();
SomeClass instance2 = instance1;

But the following will throw a warning and a type of String will not be implied in any of the class's methods:

SomeClass instance1 = new SomeClass();
SomeClass<String> instance2 = instance1;

I think I just figured it out, though, so if so I am sorry to waste everyone's time. Does this work because instance2 is creating a pointer rather than a new object, and a pointer can't change the behavior of the object it is pointing to?

解决方案

Generics are compile time only. Basically when the code gets compiled the parameterized types are erased and replaced with casts.

Consider something like the following:

class SomeClass<T> {
    T value;

    T get() {
        return value;
    }

    void set(T val) {
        value = val;
    }
}

When you declare a new SomeClass it looks like what happens is like this:

class SomeClass {
    String value; // "value is now a String"

    String get() {
        return value;
    }

    void set(String val) {
        value = val;
    }
}

But that is not what actually happens. What actually happens is that SomeClass is always like this:

class SomeClass {
    Object value; // erasure of T is Object

    Object get() {
        return value;
    }

    void set(Object val) {
        value = val;
    }
}

And when you have a SomeClass<String>, whenever you say String someString = someClass.get();, the compiler inserts a cast from Object to String. There is no behavioral difference between a raw time and a parameterized type at run time, only whether there is a cast. That's why raw types are "bad", because there is basically no difference between a raw type and not using generics.

Try this:

SomeClass<String> pam = new SomeClass<String>();

((SomeClass)pam).set(new Integer(0));

System.out.println(((SomeClass)pam).get()); // prints 0
System.out.println(pam.get()); // ClassCastException

So to be clear, when you do this:

SomeClass<String> instance1 = new SomeClass<>();
SomeClass instance2 = instance1;

No types are "passed". instance2 is not a SomeClass<String>.

When you do this:

SomeClass instance1 = new SomeClass();
SomeClass<String> instance2 = instance1;

You get a warning because it's unsafe. There's no guarantee that instance1's value is a String but it will be casted to one if you call get on instance2.

Given the following snippet:

SomeClass<String> instance1 = new SomeClass<String>();
SomeClass instance2 = instance1;

System.out.println(instance1.get());
System.out.println(instance2.get());

The print statements compile to the following bytecode:

getstatic PrintStream System.out
aload_1 instance1
invokevirtual Object SomeClass.get()           // instance1.get() returns Object
checkcast String                               // which is casted to String
invokevirtual void PrintStream.println(String) // call println for String
getstatic PrintStream System.out
aload_2 instance2
invokevirtual Object SomeClass.get()           // instance2.get() returns Object
invokevirtual void PrintStream.println(Object) // call println for Object

As you can see, there's no difference except for the cast.

这篇关于为什么我不能将原始类型分配给参数化类型? (JAVA)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆