什么是原始类型,为什么不应';我们不能用它吗? 问题: Java中的原始类型是什么?为什么我经常听说不应该在新代码中使用它们 如果我们不能使用原始类型,那么还有什么替代方案,如何更好
Java中的“原始”类型是一个非泛型类,它处理“原始”对象,而不是类型安全的泛型类型参数 例如,在Java泛型可用之前,您将使用如下集合类:什么是原始类型,为什么不应';我们不能用它吗? 问题: Java中的原始类型是什么?为什么我经常听说不应该在新代码中使用它们 如果我们不能使用原始类型,那么还有什么替代方案,如何更好,java,generics,raw-types,Java,Generics,Raw Types,Java中的“原始”类型是一个非泛型类,它处理“原始”对象,而不是类型安全的泛型类型参数 例如,在Java泛型可用之前,您将使用如下集合类: LinkedList list = new LinkedList(); list.add(new MyObject()); MyObject myObject = (MyObject)list.get(0); 当您将对象添加到列表中时,它并不关心它是什么类型的对象,当您从列表中获取它时,您必须显式地将其强制转换为您期望的类型 使用泛型可以删除“未知”因素
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
当您将对象添加到列表中时,它并不关心它是什么类型的对象,当您从列表中获取它时,您必须显式地将其强制转换为您期望的类型
使用泛型可以删除“未知”因素,因为必须明确指定列表中可以包含的对象类型:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
LinkedList=新建LinkedList();
添加(新的MyObject());
MyObject MyObject=list.get(0);
请注意,对于泛型,您不必强制转换来自get调用的对象,集合是预定义的,仅用于MyObject。这正是泛型的主要驱动因素。它将运行时错误的来源更改为可以在编译时检查的内容。什么是原始类型?为什么我经常听到不应该在新代码中使用它们
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
“原始类型”是使用泛型类而不为其参数化类型指定类型参数,例如使用List
而不是List
。当泛型被引入Java时,几个类被更新为使用泛型。将这些类用作“原始类型”(不指定类型参数)允许遗留代码仍在编译
“原始类型”用于向后兼容。不建议在新代码中使用它们,因为使用带有类型参数的泛型类可以实现更强的类型,这反过来可能会提高代码的可理解性,并导致更早发现潜在问题
如果我们不能使用原始类型,那么还有什么替代方案,如何更好
首选的替代方法是按预期使用泛型类-使用合适的类型参数(例如列表
)。这允许程序员更具体地指定类型,向未来的维护人员传达更多关于变量或数据结构的预期用途的含义,并且允许编译器实施更好的类型安全性。这些优点结合在一起可以提高代码质量,并有助于防止引入某些编码错误
例如,对于程序员希望确保名为“name”的列表变量只包含字符串的方法:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
List name=new ArrayList();
名称。添加(“约翰”);//好啊
name.add(新整数(1));//编译错误
原始类型是指在使用泛型类型时缺少类型参数
不应使用原始类型,因为它可能会导致运行时错误,例如在int
s的集合中插入double
Set set = new HashSet();
set.add(3.45); //ok
从集合
中检索内容时,您不知道会出现什么结果。让我们假设您期望它是全部int
s,您将它转换为Integer
;运行时出现double
3.45时出现异常
将类型参数添加到集合
,您将立即得到一个编译错误。这种先发制人的错误允许您在运行时发生故障之前修复问题(从而节省时间和精力)
Set Set=newhashset();
增加(3.45)//不行。
什么是原始类型?
Java语言规范对原始类型的定义如下:
原始类型定义为以下类型之一:
- 引用类型,通过采用泛型类型声明的名称而形成,但不附带类型参数列表
- 元素类型为原始类型的数组类型
- 原始类型
R
的非静态
成员类型,它不是从R
的超类或超接口继承的
下面是一个例子来说明:
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] args) {
MyType mt; // warning: MyType is a raw type
MyType.Inner inn; // warning: MyType.Inner is a raw type
MyType.Nested nest; // no warning: not parameterized type
MyType<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
上面的代码运行得很好,但假设您还有以下代码:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
现在我们在运行时遇到了麻烦,因为names
包含的内容不是字符串的实例
假设,如果您希望名称
仅包含字符串
,您可能仍然可以使用原始类型,自己手动检查每个添加
,然后手动将名称
中的每个项转换为字符串
更好的方法是不使用原始类型,而是让编译器利用Java泛型的强大功能为您完成所有工作
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Java中的泛型是不变的。列表
不是列表
,因此以下内容将生成编译器警告:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
编译器在保护您免受潜在违反列表的类型不变性方面做得非常出色!如果您将参数声明为原始类型列表
,那么代码将编译,并且您将违反列表名称
的类型不变量
原始类型是对该类型的擦除
返回JLS 4.8:
可以将参数化类型的擦除
或元素类型为参数化类型的数组类型的擦除用作类型这种类型称为原始类型。
[……]
原始类型的超类(分别是超级接口)是泛型类型的任何参数化的超类(超级接口)的擦除
未从其超类或超接口继承的原始类型C
的构造函数、实例方法或非static
字段的类型是与C
对应的泛型声明中删除其类型相对应的原始类型
更简单地说,当使用原始类型时
void appendNewObject(List<Object> list) {
list.add(new Object());
}
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
class MyType<E> {
List<String> getNames() {
return Arrays.asList("John", "Mary");
}
public static void main(String[] args) {
MyType rawType = new MyType();
// unchecked warning!
// required: List<String> found: List
List<String> names = rawType.getNames();
// compilation error!
// incompatible types: Object cannot be converted to String
for (String str : rawType.getNames())
System.out.print(str);
}
}
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings
//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
int id;
public int compareTo(Object other)
{return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
int id;
public int compareTo(MyCompareAble other)
{return this.id - other.id;}
}
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
private static List<String> list = new ArrayList<String>();
private static List<String> list = new ArrayList<String>();
private static List<String> list = new ArrayList<String>();
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Box<Integer> intBox = new Box<>();
Box rawBox = new Box();
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
public static void main(String[] args) throws IOException {
Map wordMap = new HashMap();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
public static void main(String[] args) throws IOException {
// replace with TreeMap to get them sorted by name
Map<String, Integer> wordMap = new HashMap<String, Integer>();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
Entry<String, Integer> entry = i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
}
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23); //prone to compile time error.
//error: no suitable method found for add(int)
arr.add("hello"); //alone this compile but raise the warning.
arr.add(23); //again prone to compile time error.
//error: no suitable method found for add(int)
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Box<Integer> intBox = new Box<>();
Box rawBox = new Box();
public class StrangeClass<T> {
@SuppressWarnings("unchecked")
public <X> X getSomethingElse() {
return (X)"Testing something else!";
}
public static void main(String[] args) {
final StrangeClass<String> withGeneric = new StrangeClass<>();
final StrangeClass withoutGeneric = new StrangeClass();
final String value1,
value2;
// Compiles
value1 = withGeneric.getSomethingElse();
// Produces compile error:
// incompatible types: java.lang.Object cannot be converted to java.lang.String
value2 = withoutGeneric.getSomethingElse();
}
}
import java.util.*;
public final class AvoidRawTypes {
void withRawType() {
//Raw List doesn't self-document,
//doesn't state explicitly what it can contain
List stars = Arrays.asList("Arcturus", "Vega", "Altair");
Iterator iter = stars.iterator();
while (iter.hasNext()) {
String star = (String) iter.next(); //cast needed
log(star);
}
}
void withParameterizedType() {
List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
for (String star: stars) {
log(star);
}
}
private void log(Object message) {
System.out.println(Objects.toString(message));
}
}