1.所有类继承Object
Java 中的所有类都隐式继承该类Object
。
我们将在 Java Core 任务中分析继承是什么以及它在 Java 中是如何工作的。现在,我们将考虑由此得出的一个简单事实:
任何类的对象都可以分配给Object
变量。例子:
代码 | 笔记 |
---|---|
|
变量存储对对象o 的引用Scanner |
|
变量存储对对象o 的引用String |
|
变量存储对对象o 的引用Integer |
|
变量存储对对象o 的引用String |
这是好消息结束的地方。编译器不会跟踪保存在变量中的对象的原始类型Object
,因此除了类的方法之外,您将无法 调用已保存对象Object
的方法。
如果你需要调用与对象的原始类型相关联的方法,那么你需要先将对它的引用保存在正确类型的变量中,然后调用该变量的方法:
代码 | 笔记 |
---|---|
|
该程序将无法编译。该类Object 没有nextInt() 方法。 |
|
这会起作用。这里我们使用类型转换运算符 将对对象 的引用保存 Scanner 在变量中。 Scanner |
您不能直接将Object
变量分配给 Scanner 变量,即使该Object
变量存储了对对象的引用Scanner
。但是,如果您使用您已经知道的类型转换运算符,就可以做到这一点。这是它的一般外观:
Type name1 = (Type) name2;
其中name1
是变量名Type
,是存储对象引用name2
的变量名。Object
Type
类型转换
如果变量的类型和对象的类型不匹配,则会ClassCastException
抛出 a 。例子:
代码 | 笔记 |
---|---|
|
运行时会报错:这里会抛出 a ClassCastException |
在 Java 中有一种方法可以避免这种错误:我们通过检查存储在变量中的对象的类型来做到这一点:
name instanceof Type
运算instanceof
符检查name
变量是否为Type
对象。
例如,让我们在不同对象的数组中查找一个字符串:
代码 | 笔记 |
---|---|
|
自动装箱会将这些值分别转换为Integer 、String 和Double 。遍历对象数组 如果对象是 a String 将其保存到 String 变量在屏幕上显示变量。 |
2. 为什么会出现泛型——集合
让我们回到集合。
Java 开发人员一创建该类ArrayList
,就希望它具有通用性,以便它可以存储任何类型的对象。所以他们使用 s 的数组Object
来存储元素。
这种方法的优势在于您可以将任何类型的对象添加到集合中。
当然,也有几个弱点。
缺点 1。
从集合中检索元素时,总是需要编写类型转换运算符:
代码 | 笔记 |
---|---|
|
创建一个集合来存储对Object 对象的引用用数字填充集合 10 , 20 , ... 100 ; 对集合的元素求和 Typecasting 是必要的 |
缺点2。
不能保证集合包含特定类型的元素
代码 | 笔记 |
---|---|
|
创建一个集合来存储对Object 对象的引用我们用表示为对象的数字填充集合 Double :0.0 , 2.5 , 5.0 , ...对集合的元素求和 会出现错误:a Double cannot be cast to anInteger |
数据可以放在任何地方的集合中:
- 用另一种方法
- 在另一个程序中
- 从一个文件
- 通过网络
缺点3。
集合中的数据可能会被意外更改。
您可以将充满数据的集合传递给某种方法。该方法由不同的程序员编写,将其数据添加到您的集合中。
集合的名称并没有明确指出其中可以存储哪些类型的数据。即使你给你的变量一个明确的名字,对它的引用也可以传递给一打方法,而这些方法肯定不会知道变量的原始名称。
3.泛型
在 Java 中,所有这些问题都被这个叫做泛型的很酷的东西消除了。
在 Java 中,泛型意味着向类型添加类型参数的能力。结果是一个复杂的复合类型。这种复合类型的一般观点是这样的:
ClassName<TypeParameter>
这是一个通用类。并且它可以在您通常使用类的任何地方使用。
代码 | 描述 |
---|---|
|
创建变量 |
|
创建对象 |
|
创建数组 |
这样的集合中只能Integer
存储变量:
代码 | 描述 |
---|---|
|
ArrayList Integer 带元素的集合这是允许的 这也可以
自动装箱
但这是不允许的:编译错误 |
在 Java Collections 探索中,您将学习如何使用类型参数创建您自己的类。现在,我们将看看如何使用它们以及它们是如何工作的。
4. 泛型如何工作
实际上,泛型非常原始。
编译器只是简单地将泛型类型替换为普通类型。但是当使用泛型类型的方法时,编译器会添加一个类型转换运算符来将参数转换为类型参数:
代码 | 编译器做什么 |
---|---|
|
|
|
|
|
|
|
|
假设我们有一个对整数集合中的数字求和的方法:
代码 | 编译器做什么 |
---|---|
|
|
换句话说,泛型是一种语法糖,就像自动装箱一样,但更多一点。通过自动装箱,编译器添加了将 an 转换int
为 an 的方法Integer
,反之亦然,对于泛型,它添加了类型转换运算符。
在编译器编译带有类型参数的泛型类之后,它们只是简单地转换为普通类和类型转换运算符。有关传递给泛型类型变量的类型参数的信息将丢失。这种效果也称为类型擦除。
有时编写泛型类(带有类型参数的类)的程序员确实需要有关作为参数传递的类型的信息。在 Java Collections 任务中,您将学习如何处理这个问题以及它需要做什么。
5. 关于泛型的一些事实
这里有一些关于泛型的更有趣的事实。
类可以有多个类型参数。它看起来像这样:
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
其实,这并不奇怪。编译器可以在任何地方添加一个运算符以转换为一种类型,它可以添加多个类型转换运算符。
例子:
代码 | 笔记 |
---|---|
|
该put 方法的第一个参数是Integer ,第二个是String |
泛型类型也可以用作参数。它看起来像这样:
ClassName<TypeParameter<TypeParameterParameter>>
假设我们要创建一个列表来存储字符串列表。在这种情况下,我们会得到这样的东西:
// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");
// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");
// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
泛型类型(带有类型参数的类型)也可以用作数组类型。它看起来像这样:
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
这里没有什么神奇的事情发生:尖括号只是表示类型名称:
代码 | 非通用对应物 |
---|---|
|
|
|
|
|
|
GO TO FULL VERSION