一、泛型
* 为什么要使用泛型?
- 一般使用在集合上
** 比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本事的类型,只能是object类型,
这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型来解决。
* 在集合上如何使用泛型
- 常用集合 list set map
- 泛型语法 集合<String> 比如 List<String>
* 在泛型里面写是一个对象,String 不能写基本的数据类型 比如int (****)
** 写基本的数据类型对应包装类
short -- Short
int -- Integer
long -- Long
float -- Float
double -- Double
char -- Character
boolean -- Boolean
* 在List上使用泛型
List:有序,存入和取出的顺序一致,元素都有索引,元素可以重复
ArrayList :内部是数组数据结构,不同步。替代了Vector。查询速度快。
linkedList: 内部是链表数据结构,不同步。增删快。
Vector:内部是数组数据结构,是同步的。
//遍历list集合 有三种方式
//普通for循环 迭代器 增强for
List<String> list=new ArrayList<String>(); list.add("hello"); list.add("world"); list.add("java"); //增强for遍历 for (String s : list) { System.out.println(s); } System.out.println("-------------"); //普通for遍历 for(int i=0;i<list.size();i++){ String s1=list.get(i); System.out.println(s1); } System.out.println("-------------"); //迭代器迭代 Iterator<String> it=list.iterator(); while(it.hasNext()){ System.out.println(it.next());* 在Set上使用泛型
Set:元素不能重复,无序
HashSet:内部数据结构是哈希表,不同步
TreeSet:可以对Set集合中的元素进行排序,通过Comparable接口或覆盖comPareTo方法。
//遍历set 有两种方式
//迭代器 增强for
Set<String> set = new HashSet<String>(); set.add("hello"); set.add("world"); set.add("java"); // 增强for for (String string : set) { System.out.println(string); } System.out.println("-------------"); // 迭代器迭代 Iterator<String> it = set.iterator(); while (it.hasNext()) { System.out.println(it.next()); }结果为: (内部哈希算法排序,无序)
hello java world ------------- hello java world* 在map上面使用泛型
- map结构:key-value形式
Hashtable:内部结构是哈希表,同步。不允许null作为键和值。
HashMap:内部结构是哈希表,不同步。允许null作为键和值。
TreeSet:内部结构是二叉树,不同步。可以对Map集合中的键进行排序。
//遍历map有两种方式
//1、获取所有的key,通过key得到value 使用get方法
//2、获取key和value的关系
Map<Integer, String> hm = new HashMap<Integer, String>(); hm.put(1, "张三"); hm.put(2, "李四"); hm.put(3, "王五"); //获取所有的key,遍历key获取value Set<Integer> set=hm.keySet(); for (Integer integer : set) { System.out.println(integer+"---"+hm.get(integer)); } System.out.println("-------------"); //获取key和value的关系 Set<Entry<Integer, String>> set2=hm.entrySet(); for (Entry<Integer, String> entry : set2) { Integer key=entry.getKey(); String value=entry.getValue(); System.out.println(key+"---"+value); }
二、泛型定义在方法上
public <T> void show(T str){ }
* 写在返回值之前 void之前 <T>
* 表示定义了一个类型 这个类型是 T
* 在下面就可以使用这个类型了 T
* 定义一个数组,实现指定位置上数组元素的交换
public static <T> void swap1(T[] arr ,int a,int b) {
T temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
练习:实现一个泛型方法,接受任意一个数组,颠倒数组中所有元素
public static void main(String[] args) { Integer[] integers = { 1, 2, 3, 4, 5, 6, 9, 15 }; reverseArr(integers); String[] strings = { "hello", "world", "java" }; reverseArr(strings); } public static <T> void reverseArr(T[] arr) { for (int i = 0; i < arr.length / 2; i++) { T t = arr[i]; arr[i] = arr[arr.length - 1 - i]; arr[arr.length - 1 - i] = t; } System.out.println(Arrays.toString(arr)); }
三、泛型在类上的使用
* 在一个类上定义一个类型,这个类型可以在类里面直接使用* public class TestDemo04<T> {
//在类里面可以直接使用T的类型
T aa;
public void test11(T bb) {}
//写一个静态方法 在类上面定义的泛型,不能再静态方法里面使用
public static <A> void test12(A cc) {}
}
四、泛型的通配符
? :可以对类型进行限定
? extends E:接收E类型或者E类型的子类型对象 上限
? super E:接收E类型或者E类型的父类型 下限
一般存储元素的时候使用上限,因为这样取出都是按照上限类型来运算的。不会出现安全隐患。
对集合中的元素进行取出操作时,用下限。
五、枚举的简介
** 需要在一定的范围内取值,这个值只能是这个范围内中的任意一个。
** 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个
* 使用一个关键字 enum
** enum Color{
RED,GREEN,YELLOW;
}
* 枚举的构造方法也是私有的
* 特殊枚举的操作(了解)
** 在枚举类里面有构造方法
** 构造方法里面有参数,需要在每个实例上面都写参数
** 在枚举类里面有抽象方法
** 在枚举的每个实例里面都重写这个抽象方法
六、枚举的API操作
** name() :返回枚举的名称** ordinal() :枚举的下标,下标从0开始
** valueOf(Class<T> enumType, String name) :得到枚举的对象
** 还有两个方法,但是这两个方法不在api里面,编译的时候生成两个方法
*** valueof(String name) 转换枚举对象
*** values() 获得所有枚举对象数组
* 练习:枚举对象、枚举对象下标、枚举对象名称表示之间的转换
- //知道枚举的对象,得到枚举名称和下标
@Test
public void test1() {
//得到枚举对象
Color col = Color.RED;
//枚举名称
String name = col.name();
//枚举的下标
int idx = col.ordinal();
System.out.println(name+" "+idx);
}
- //知道枚举的名称,得到枚举的对象和下标
@Test
public void test2() {
String name1 = "GREEN";
//得到对象
Color col = Color.valueOf(name1);
//枚举下标
int idx1 = col.ordinal();
System.out.println(idx1);
}
- //知道枚举的下标,得到枚举的对象和名称
@Test
public void test3() {
int idx2 = 2;
//得到枚举的对象
Color[] cols = Color.values();
//根据下标得到对象
Color col = cols[idx2];
//得到枚举的名称
String name = col.name();
System.out.println(name);
}
七、静态导入(了解)
* 可以在代码里面,直接使用静态导入方式,导入静态方法或者常量* import static XX.XX.xxx
import static java.lang.System.out; import static java.util.Arrays.sort; import static java.util.Arrays.toString; public class TestDemo1 { public static void main(String[] args) { out.println("hello"); int[] arr1 = {10,1,3,20,15}; sort(arr1); //System.out.println(toString(arr1)); } }
八、自动拆装箱
* 装箱** 把基本的数据类型转换成包装类
* 拆箱
** 把包装类转换成基本的数据类型
** //自动装箱
Integer i = 10;
//自动拆箱
int m = i;
** 在jdk1.4里面如何实现装箱和拆箱
- //在jdk1.4里面实现拆装箱
public void test1() {
//装箱
Integer m = new Integer(10);
//拆箱
int a = m.intValue();
}
** jdk是会向下兼容
- 比如 jdk1.4里面写的代码,这个时候到5.0里面也可以运行
** 练习:向下兼容
== 执行的结果是会调用 doSomething(double m)
== 首先在jdk1.4里面肯定调用这个方法,如果调用下面的方法,需要类型转换,但是jdk1.4不能实现自动拆装箱
== 由于jdk是向下兼容,所以,在jdk1.4调用这个方法,在jdk5.0里面还是会调用这个方法
public static void main(String[] args) {
doSomething(10); //double......
}
public static void doSomething(double m) {
System.out.println("double......");
}
public static void doSomething(Integer a){
System.out.println("integer.....");
}
九、增强for循环
* 语法 for(变量类型 变量名: 要迭代的数组或集合) {}- for(String s : list) {
System.out.println(s);
}
* 使用场景: 数组;实现Iterable接口的集合 可以使用增强for循环
* 在集合上使用增强for循环遍历
list set 实现了Iterator接口,所以可以使用增强for循环
map不能使用增强for循环,没有实现Iterator接口,所以不能使用增强for循环
可以通过Map的entrSet方法或者KeySet方法现获取到Set集合在使用增强for
* 增强for循环出现目的:为了替代迭代器
** 增强for底层就是迭代器实现的
十、可变参数
* 可变参数可以应用在什么场景:** 实现两个数的相加,实现三个数的相加 四个数的相加
-- 如果实现的多个方法,这些方法里面逻辑基本相同,唯一不同的是传递的参数的个数,可以使用可变参数
* 可变参数的定义方法:数据类型...数组的名称
* 理解为一个数组,这个数组存储传递过来的参数
- 代码
public static void add1(int...nums) {
//nums理解为一个数组,这个数组存储传递过来的参数
//System.out.println(nums.length);
int sum = 0;
//遍历数组
for(int i=0;i<nums.length;i++) {
sum += nums[i];
}
System.out.println( sum);
}
* 注意的地方
(1)可变参数需要写在方法的参数列表中,不能单独定义
(2)在方法的参数列表中只能有一个可变参数
(3)方法的参数列表中的可变参数,必须放在参数最后
- add1(int a,int...nums)