如果实例没有分配通用类型,则泛型将用于每个循环问题 [英] Generics in for each loop problem if instance does not have generic type assigned

查看:110
本文介绍了如果实例没有分配通用类型,则泛型将用于每个循环问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释为什么明确需要为ForEachLoop实例指定泛型类型?



为什么编译器会抱怨: 类型不匹配:无法从元素类型Object转换为字符串



JDK 1.5.0_09

  import java.util.ArrayList; 
import java.util.Collection;

public class ForEachLoop< T> {

public static void main(String [] args){

//非功能版本
ForEachLoop f = new ForEachLoop();

//功能版本
// ForEachLoop<整数> f = new ForEachLoop();

//类型不匹配:无法从元素类型Object转换为字符串
for(String a:f.getStrings()){
System.out.println(a);
}
}

public Collection< String> getStrings(){
Collection< String> strings = new ArrayList< String>();
strings.add(Hello);
返回字符串;
}

}


解决方案

这是一个相当常见的错误:

  ForEachLoop f = new ForEachLoop(); 

应该是

  foreach循环<东西> f = new ForEachLoop< Something>(); 

如果您使用原始类型(您不应该这样做),编译器将删除所有通用信息即使它不是类型参数T,也可以使它与pre 1.5代码兼容。



如果您要编写Java 1.4或更低版本,请仅使用原始类型,在这种情况下,你不应该有任何泛型。在字节码级别,该方法在类型擦除后返回一个Collection(raw)。通常,如果实例具有泛型类型集,那么当您尝试对集合执行 get 时,编译器将使用通用信息来决定它应该返回一个String,然后在字节码级别,它会自动将它从Collection收到的Object转换为String(因为它保证是一个String)。但是,如果使用原始类型,编译器将忽略所有通用信息,并且不会自动为您再次投射对象。



编辑:In在原始类型的部分有这些东西:



上面的规则的另一个含义是一个通用的内部类原始
类型本身只能用作原始
类型:

pre $ class Outer< T> {
class Inner< S> {
S s;




$ b $ p
$ b

不可能将Inner作为
部分原始类型(罕见类型)

  Outer.Inner< Double> x = null; //非法
Double d = x.s;

因为Outer本身是原始的,所以它的所有内部类都是
,包括
Inner,所以
不可能传递任何类型参数。

使用原始类型只允许
作为让步以兼容
遗留代码。强烈建议在
通用性引入Java编程
语言后编写的
代码中使用原始类型。
有可能未来版本的
Java编程语言将
禁止使用原始类型。



尝试使用

参数化类型的类型成员用作原始类型是一个编译时错误。



意味着对稀有
类型的禁止延伸到
限定类型被参数化的情况,但
我们尝试使用内部类作为
原始类型:

 外部< Integer> .Inner x = null; //非法

这与上面讨论的
情况相反。这种半烘焙的
类型没有实际的
理由。在遗留代码中,不使用类型
参数。在非遗留的
代码中,我们应该正确使用泛型类型
并传递所有必需的
实际类型参数。

请注意,Inner类具有独立于Outer类的类型参数,并且它仍然被擦除。基本上他们不希望我们在同一个实例中混合原始类型和泛型类型,因为它在任何版本中都没有意义(在1.5之前,通用部分将是错误,在1.5+以上,原始类型不鼓励,以及甚至可能会从未来的版本中删除)



然后也是这样:
$ b


原始
类型C的构造函数(§8.8),
实例方法(§8.8,§9.4)或
非静态字段(§8.3)M的类型从它的
超类或超接口继承的是在与C相对应的通用
声明中的
类型的擦除。原始类型的静态成员
类型
C与它在
泛型声明中对应于
C的类型相同。

传递$ b $是一个编译时错误b实际类型参数转换为原始类型的非静态
类型成员,该成员不是从其超类或
超接口继承的


blockquote>

其中说构造函数,实例方法和非静态字段在原始实例中将被视为原始数据。无论如何,静态成员将被视为通用名称,因为它们不需要加入实例。


Could someone please explain to me why there is explicit need to assign generic type for ForEachLoop instance?

Why compiler complains: Type mismatch: cannot convert from element type Object to String?

JDK 1.5.0_09

import java.util.ArrayList;
import java.util.Collection;

public class ForEachLoop<T> {

public static void main(String[] args) {

    // Non functional version
    ForEachLoop f = new ForEachLoop(); 

    // Functional version
    //ForEachLoop<Integer> f = new ForEachLoop();

            // Type mismatch: cannot convert from element type Object to String
    for(String a : f.getStrings()) {
        System.out.println(a);
    }
}

public Collection<String> getStrings() {
    Collection<String> strings = new ArrayList<String>();
    strings.add("Hello");
    return strings;
}

} 

解决方案

This is a rather common mistake:

ForEachLoop f = new ForEachLoop(); 

should be

ForEachLoop<Something> f = new ForEachLoop<Something>();

If you use the raw type (which you shouldn't) the compiler will erase all generic information for that instance even if it's not the type parameter T, to make it compatible with pre 1.5 code.

Only use raw types if you're writing for Java 1.4 or less, in which case you shouldn't have any generics whatsoever. At the bytecode level the method returns a Collection (raw) after type erasure. Normally, if the instance has the generic type set, when you try to do get on the collection, the compiler will use the generic information to decide that it should return a String, and then at the bytecode level it automatically casts the Object it receives from the Collection to String (since it's guaranteed to be a String). But if you use the raw type the compiler will ignore all generic information and will not automatically cast the object for you anymore.

Edit: In the section on Raw Types there are these things:

Another implication of the rules above is that a generic inner class of a raw type can itself only be used as a raw type:

class Outer<T>{
  class Inner<S> {
    S s;
  }
}

it is not possible to access Inner as partially raw type (a "rare" type)

Outer.Inner<Double> x = null; // illegal
Double d = x.s;

because Outer itself is raw, so are all its inner classes, including Inner, and so it is not possible to pass any type parameters to it.

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

It is a compile-time error to attempt to use a type member of a parameterized type as a raw type.

This means that the ban on "rare" types extends to the case where the qualifying type is parameterized, but we attempt to use the inner class as a raw type:

Outer<Integer>.Inner x = null; // illegal

This is the opposite of the case we discussed above. There is no practical justification for this half baked type. In legacy code, no type parameters are used. In non-legacy code, we should use the generic types correctly and pass all the required actual type parameters.

Notice that the Inner class has it's own type parameter independent of the one of the Outer class, and it still gets erased. Basically they don't want us mixing raw and generic types on the same instance, since it doesn't make sense in any version (in pre 1.5, the generic part will be an error, in 1.5+ the raw type is discouraged, and may even be removed from future versions)

Then there's also this:

The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.

It is a compile-time error to pass actual type parameters to a non-static type member of a raw type that is not inherited from its superclasses or superinterfaces.

which says that constructors, instance methods and non-static fields will be treated as raw in a raw instance. Static members will be treated as generic anyway, since they don't require an instance to be accesed.

这篇关于如果实例没有分配通用类型,则泛型将用于每个循环问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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