8.泛型概述和基本使用
回想一下,我们的数组
String[] strArray = new String[3];
strArray[0] = "hello";
strArray[1] = "world";
strArray[2] = 10;
集合也模仿着数组的这种做法,
在创建对象的时候明确元素的数据类型。这样就不会在有问题了。
而这种技术被称为:泛型。
泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
格式:
<数据类型>
此处的数据类型只能是引用类型。
好处:
A:
把运行时期的问题提前到了编译期间
B:
避免了强制类型转换
C:优化了程序设计,解决了黄色警告线
public static void main(String[] args) {
// 创建
ArrayList
array = new ArrayList
();
// 添加元素
array.add("hello");
array.add("world");
array.add("java");
// 遍历
Iterator
it = array.iterator();
while (it.hasNext()) {
// ClassCastException
// String s = (String) it.next();
String s = it.next();
System.out.println(s);
}
}
2.泛型在哪些地方使用呢?
看API,如果类,接口,抽象类后面跟的有就说要使用泛型。
一般来说就是在集合中使用。
以下用ArrayList存储字符串元素,并遍历。用泛型改进代码
public static void main(String[] args) {
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
Iterator it = array.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------");
for (int x = 0; x < array.size(); x++) {
String s = array.get(x);
System.out.println(s);
}
}
3
.JDK7的新特性--------泛型推断
创建集合对象
ArrayList array = new ArrayList();//一般情况下
JDK7的新特性:
泛型推断。
ArrayList array = new ArrayList<>();
但是不建议这样使用。
ArrayList array = new ArrayList();//还是这样写
4.泛型类:把泛型定义在类上
举例
=============================================
public class ObjectTool
{
private
T obj;
public
T getObj() {
return obj;
}
public void setObj(
T obj) {
this.obj = obj;
}
}
====================================================
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool
ot = new ObjectTool
();
// ot.setObj(new Integer(27)); //这个时候编译期间就过不去
ot.setObj(new String("林青霞"));
String s = ot.getObj();
System.out.println("姓名是:" + s);
ObjectTool
ot2 = new ObjectTool
();
// ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去
ot2.setObj(new Integer(27));
Integer i = ot2.getObj();
System.out.println("年龄是:" + i);
}
}
5. 泛型方法:把泛型定义在方法上(这个时候与泛型类无关!)
原始做法
============================
public class ObjectTool
{
public void show(
T t) {
System.out.println(t);
}
}
============================
ObjectTool ot = new ObjectTool
();
ot.show("hello");
ObjectTool ot2 = new ObjectTool
();
ot2.show(100);
ObjectTool ot3 = new ObjectTool
();
ot3.show(true);
// 如果还听得懂,那就说明泛型类是没有问题的
// 但是呢,谁说了我的方法一定要和类的类型的一致呢?
// 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢?
改进(不定义泛型类,但定义了一个普通类的背后定义一个泛型方法)
ObjectTool.java
public class ObjectTool {
public
void show(
T t) {
System.out.println(t);
}
}
// 定义泛型方法后 ObjectToolDemo.java
ObjectTool ot = new ObjectTool();
ot.show("hello");
ot.show(100);
ot.show(true);
6.泛型接口:把泛型定义在接口上
================================================
Inter.java(定义一个接口,而且是泛型接口)
public interface Inter {
public abstract void show(T t);
}
================================================
InterImpl.java(用一个类去实现上面的泛型接口)
//实现类在实现接口的时候
//第一种情况:已经知道该是什么类型的了(用得比较少)
//public class
InterImpl implements
Inter {
//
// @Override
// public void show(
String t) {
// System.out.println(t);
// }
// }
//第二种情况:还不知道是什么类型的(
这种情况最常见,推荐使用,说白了,就是用泛型类实现泛型接口)
public class
InterImpl implements
Inter {
@Override
public void show(
T t) {
System.out.println(t);
}
}
=================================
public static void main(String[] args) {
// 第一种情况的测试
// Inter i = new InterImpl();//
只能是String,否则会报错
// i.show("hello");
// // 第二种情况的测试
Inter i = new InterImpl();
i.show("hello");
Inter ii = new InterImpl();
ii.show(100);
}
7.泛型高级之通配符
泛型高级(通配符)
?:
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E:向下限定,E及
其子类
? super E:向上限定,E及
其父类
背景
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
泛型如果明确的写的时候,前后必须一致
?表示任意的类型都是可以的
? extends E:向下限定,E及其子类
? super E:向上限定,E极其父类
(留意以上截图哪些行报错了)
8.JDK5的新特性----增强for
JDK5的新特性:自动拆装箱,泛型,增强for,静态导入,可变参数,枚举
增强for:是for循环的一种。
格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
好处:
简化了数组和
集合的遍历。
弊端: 增强for的目标不能为null。
*如何解决呢?
对增强for的目标先进行不为null的判断,
然后再使用。
==========================================
public static void main(String[] args) {
// 定义一个
int数组
int[] arr = { 1, 2, 3, 4, 5 };
for (int x = 0; x < arr.length; x++) {
System.out.println(arr[x]);
}
System.out.println("---------------");
// 增强for
for (int x : arr) {
System.out.println(x);
}
System.out.println("---------------");
// 定义一个
字符串数组
String[] strArray = { "林青霞", "风清扬", "东方不败", "刘意" };
// 增强for
for (String s : strArray) {
System.out.println(s);
}
System.out.println("---------------");
//
定义一个集合(重点留意这个遍历的简化)
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
// 增强for
for (
String s : array) {
System.out.println(s);
}
System.out.println("---------------");
}
==============================================================
弊端: 增强for的目标不能为null。如下面所示
List list =
null;
//
NullPointerException
// 这个s是我们从list里面获取出来的,在
获取前,它肯定还要做一个
判断
// 说白了,这就是迭代器的功能
//又要获取又要判断,所以抛出异常
//改进
if (list != null) { //改进后,加一个判断
for (String s : list) {
System.out.println(s);
}
}
还有一个值得注意的问题
增强for其实就是(用来替代)迭代器
迭代器遍历集合,集合修改集合会产生
并发修改异常。换句话说,增强for就是替代了迭代器(的作用)
详见以下这个例子
// 增强for其实是用来替代迭代器的
//
ConcurrentModificationException
// for (String s : array) {
// if ("world".equals(s)) {
// array.add("javaee");
// }
// }
// System.out.println("array:" + array);
9.JDK5的新特性-----静态导入(意义不大,能看懂即可)
*静态导入的注意事项:
A:
方法必须是静态的
B:如果有多个同名的静态方法,容易不知道使用谁?这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。
10.使用Eclipse快速制作方法
或者选中a + b来做方法也可以
11.JDK5的新特性-----可变参数
可变参数:定义方法的时候不知道该定义多少个参数
格式:
修饰符 返回值类型 方法名(
数据类型… 变量名){
}
注意:
这里的
变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个(也就是说,可以是
method(int a, int...b),但不可以是method(int...b,int a) 。)
public static void main(String[] args) {
// 2个数据求和
int a = 10;
int b = 20;
int result = sum(a, b);
System.out.println("result:" + result);
// 3个数据的求和
int c = 30;
result = sum(a, b, c);
System.out.println("result:" + result);
// 4个数据的求和
int d = 30;
result = sum(a, b, c, d);
System.out.println("result:" + result);
需求:我要写一个求和的功能,到底是几个数据求和呢,我不太清楚,但是我知道在调用的时候我肯定就知道了
为了解决这个问题,Java就提供了一个东西:可变参数
result = sum(a, b, c, d, 40);
System.out.println("result:" + result);
result = sum(a, b, c, d, 40, 50);
System.out.println("result:" + result);
}
public static int sum
(int... a) {
// System.out.println(a);
//return 0;
int s = 0;
//在这里,其实
a是一个数组
for(int x : a){
s +=x;
}
return
s;
}
通过反编译发现,其实还是数组
12.Arrays工具类的asList()方法(接收
可变参数)
public static List asList(
T... a):把数组转成集合
注释:第一个表示这是一个泛型方法名叫asList
第二个表示返回值是一个泛型接口---List
public static void main(String[] args) {
// 定义一个数组
// String[] strArray = { "hello", "world", "java" };
// List list = Arrays.asList(strArray);
List list = Arrays.asList("hello", "world", "java");
// UnsupportedOperationException
// list.add("javaee");
// UnsupportedOperationException
// list.remove(1);
list.set(1, "javaee");
for (String s : list) {
System.out.println(s);
}
}
注意事项:
虽然可以把数组转成集合,但是
集合的长度不能改变。
asList接收可变参数,Arrays.asList("hello", "world", "java");//可以
Arrays.asList("hello", "world");//也可以
13.一个案例:集合
嵌套存储和遍历元素的案例
集合的嵌套遍历
需求:
我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList
但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList。
而我现在有多个ArrayList。也要用集合存储,怎么办呢?
案例图解
public static void main(String[] args) {
// 创建大集合
ArrayList
> bigArrayList = new ArrayList>();
// 创建第一个班级的学生集合
ArrayList firstArrayList = new ArrayList();
// 创建学生
Student s1 = new Student("唐僧", 30);
Student s2 = new Student("孙悟空", 29);
Student s3 = new Student("猪八戒", 28);
Student s4 = new Student("沙僧", 27);
Student s5 = new Student("白龙马", 26);
// 学生进班
firstArrayList.add(s1);
firstArrayList.add(s2);
firstArrayList.add(s3);
firstArrayList.add(s4);
firstArrayList.add(s5);
// 把第一个班级存储到学生系统中
bigArrayList.add(firstArrayList);
// 创建第二个班级的学生集合
ArrayList secondArrayList = new ArrayList();
// 创建学生
Student s11 = new Student("诸葛亮", 30);
Student s22 = new Student("司马懿", 28);
Student s33 = new Student("周瑜", 26);
// 学生进班
secondArrayList.add(s11);
secondArrayList.add(s22);
secondArrayList.add(s33);
// 把第二个班级存储到学生系统中
bigArrayList.add(secondArrayList);
// 创建第三个班级的学生集合
ArrayList thirdArrayList = new ArrayList();
// 创建学生
Student s111 = new Student("宋江", 40);
Student s222 = new Student("吴用", 35);
Student s333 = new Student("高俅", 30);
Student s444 = new Student("李师师", 22);
// 学生进班
thirdArrayList.add(s111);
thirdArrayList.add(s222);
thirdArrayList.add(s333);
thirdArrayList.add(s444);
// 把第三个班级存储到学生系统中
bigArrayList.add(thirdArrayList);
// 遍历集合
for (ArrayList array : bigArrayList) {
for (Student s : array) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
14.第二个案例
用数组实现,
但是数组的长度是固定的,长度不好确定。
所以我们使用集合实现。
分析:
A:创建产生随机数的对象
B:创建一个存储随机数的集合。
C:定义一个统计变量。从0开始。
D:判断统计遍历是否小于10
是:先产生一个随机数,判断该随机数在集合中是否存在。
如果不存在:就添加,统计变量++。
如果存在:就不搭理它。
否:不搭理它
E:遍历集合
实现代码参考
public static void main(String[] args) {
// 创建产生随机数的对象
Random r = new Random();
// 创建一个存储随机数的集合。
ArrayList array = new ArrayList();
// 定义一个统计变量。从0开始。
int count = 0;
// 判断统计遍历是否小于10
while (count < 10) {
//先产生一个随机数
int number =
r.nextInt(20) + 1;
//判断该随机数在集合中是否存在。
if(!array.
contains(number)){
//如果不存在:就添加,统计变量++。
array.add(number);
count++;
}
}
//遍历集合
for(Integer i : array){
System.out.println(i);
}
}
15.案例3
需求:键盘录入多个数据,
以0结束,要求在控制台输出这多个数据中的
最大值
分析:
A:创建键盘录入数据对象
B:键盘录入多个数据,我们不知道多少个,所以用集合存储
C:以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
D:把集合转成数组
E:对数组排序
F:获取该数组中的最大索引的值
示例代码
public static void main(String[] args) {
// 创建键盘录入数据对象
Scanner sc = new Scanner(System.in);
// 键盘录入多个数据,我们不知道多少个,所以用集合存储
ArrayList array = new ArrayList();
// 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
while (true) {
System.out.println("请输入数据:");
int number = sc.nextInt();
if (number != 0) {
array.add(number);
} else {
break;
}
}
// 把集合转成数组
// public T[] toArray(T[] a)
Integer[] i = new Integer[array.size()];
// Integer[] ii = array.toArray(i);
array.toArray(i);
// System.out.println(i);
// System.out.println(ii);
// 对数组排序
// public static void sort(Object[] a)
Arrays.sort(i);
// 获取该数组中的最大索引的值
System.out.println("数组是:" + arrayToString(i) + "最大值是:"
+ i[i.length - 1]);
}
public static
String
arrayToString(Integer[] i) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int x = 0; x < i.length; x++) {
if (x == i.length - 1) {
sb.append(i[x]);
} else {
sb.append(i[x]).append(", ");
}
}
sb.append("]");
return
sb.toString();
}
几个注意或者有疑问的地方