泛型的简介
为什么要使用泛型
一般使用在集合上
比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本来类型,只能是 object 类型,这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型类来解决。
在集合上如何使用泛型
常用集合 list set map
泛型语法 集合<String> 比如List<String>
在泛型里面写是一个对象,String 不能写基本的数据类型 比如 int
写基本的数据类型对应包装类
byte —— Byte
short —— Short
int —— Integer
long —— Long
float —— Float
double —— Double
char —— Character
boolean —— Boolean
在list上面使用泛型
list的三种实现 ArrayList LinkedList Vetor
List <String> list=new ArrayList<String>();
list.add("aaa") ;
list.add("bbb") ;
list.add("ccc") ;
//遍历list
//普通 for 循环
for(int i=0;i<list.size();i++){
String s=list.get(i);
System.out.print(s);
}
//使用增强 for
for(String s1:list){
System.out.print(s1);
}
//使用迭代器遍历
Iterator<String> it=list.iterator();
while(it.hasNext()){
System.out.print(it.next());
}
在set上使用泛型
Set <String> set=new HashSet<String>();
list.add("www") ;
list.add("qqq") ;
list.add("zzz") ;
//遍历 set ,有两种方式
//for(String s2 : set){System.out.print(s2);
}
//使用迭代器遍历
Iterator<String> it1=set.iterator();
while(it1.hasNext()){
System.out.print(it1.next());
}
在map上面使用泛型
map结构:key-value形式
泛型使用在方法上
定义一个数组,实现指定位置上数组元素的交换
方法逻辑相同, 只是数据类型不同,这个时候使用泛型方法
使用泛型方法 需要定义一个类型 使用大写字母表示 T:这个T表示任意的类型
写在返回值之前 void之前<T>
泛型在类上的使用
在一个类上定义一个类型,这个类型可以在类里面直接使用
public class TestDemo04<T>{
//在类里面可以直接使用T的类型
T aa;
}
public void test11(T bb){}
//写一个静态方法 在类上面定义的泛型 不能再静态方法里面使用
public static< A> void test12(A cc ){
}
枚举的简介
什么是枚举
需要在一定的范围内取值,这个值只能是这个范围内中的任意一个
使用一个关键字enum
enum Color3{
RED,GREEN,YELLOW
}
枚举的构建方法是私有的
特殊枚举的操作
在枚举类里面有构造方法
构造方法里面有参数,需要在每个实例上面都写参数
在枚举类里有抽象方法
在枚举的每个实例里面都重写这个抽象方法
枚举的api的操作
name():返回枚举的名称
ordinal():枚举的下标,下标是从0开始
ValueOf(Class<T> enumType,String name):得到枚举的对象
还有两个方法,都是这两个方法不在api里面,编译的时候生成两个方法
ValueOf(String name) 转换枚举对象
Values() 获得所有枚举对象数组
知道枚举的对象,得到枚举名称和下标
@Test
public void test1(){
//得到枚举对象
Color100 c100=Color100.RED;
//枚举名称
String name=c100.name();
//枚举的下标
int idx=c100.ordinal();
System.out.println(name+" "+idx);
}
知道枚举名称,得到枚举对象和下标
publicvoidtest(){
String name1="GREEN";
color c1=color.valueOf(name1);
//得到枚举对象
int idx=c1.ordinal(); //得到枚举下标
}enumcolor(
RED,GREEN,YELLOW
)
知道枚举下标,得到枚举对象和名称
public void test(){
int idx2=2;
color[] cs=color.values();//得到枚举对象数组
color c2=cs[idx2]; //根据下标得到对象
String name=c2.name(); //根据对象得到名称
}enumcolor(
RED,GREEN,YELLOW
)
静态导入
可以在代码里面,直接使用静态导入方式,导入静态方法或者常量
import static XX.XX.xxx
自动拆装箱
装箱:把基本的数据类型转换成包装类
拆箱:把包装类转换成基本的数据类型
//自动装箱
Integer i=10;
//自动装箱
int m=1;
在 jdk 1.4里面如何实现装箱和拆箱
publicvoidtest1(){
//装箱
Integer m = new Integer(10);
//拆箱
int a = m.intValue();
}
jdk是会向下兼容
比如子jdk1.4里面写的代码,这个时候到5.0里面也可以运行
增强for循环
语法:for(遍历出来的值:要遍历的集合){}
使用场景: 数组:实现Iterable接口的集合 可以使用增强for循环
在集合上使用增强for遍历循环
list set 实现了Iterator接口,所以可以使用增强for循环
map不能使用增强for循环 没有实现Iterator接口,所以不能使用增强for循环
增强for循环出现的目的:为了替代迭代器
增强for底层就是迭代器实现的
内容补充
1.泛型擦除
首先泛型只是出现在源代码阶段,当编译之后泛型不存在了
2.练习:实现一个泛型方法,接受任意类型的数组,颠倒数组中的所有元素
public static <T> voidreverse(T[] arr1){
for(int i=0;i<arr1.length/2;i++){
T temp =arr1[i];
arr1[i]=arr1[arr1.length-i-1];
arr1[arr1.length-i-1]=temp;
}
}
可变参数
可变参数可以应用在什么场景:
实现两个数的相加,实现三个数的相加, 四个数的相加
如果实现多个方法,这些方法里面逻辑基本相同,唯一不同的是传递的参数个数,这时候可以使用可变参数
可变参数的定义方法 数据类型...数组的名称
理解为一个数组,这个数组存储传递过来的参数
public static void add1(int...nums){
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
}
System.out.print(sum);
}
publicstaticvoidmain(String[] args){
add1(10,20);
add1(10,20,30);
add1(10,20,30,40);
}
public static void add1(int...nums){
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
}
System.out.print(sum);
}
public static void main(String[] args){
add1(10,20);
add1(10,20,30);
add1(10,20,30,40);
}
注意的地方
1.可变参数需要写在方法的参数列表中
不能单独定义
2.在方法的参数列表中只能有一个可变参数
3.方法的参数列表中的可变参数,必须放在参数最后
反射的原理
应用在一些通用性比较高的代码中
后面学到的框架 ,大多数都是使用反射来实现的
在框架开发中,都是基于配置文件开发
在配置文件中配置了类,可以通过反射得到的类中的所有内容,可以让类中的某个方法来执行
类中的所有内容: 属性,没有数的构造方法,有参数的构造方法,普通方法
反射的原理
1.首先需要 java 文件保存到本地硬盘 .java
2.编译java 文件,成 .class文件
3.使用 jvm ,把 class 文件通过类加载加载到内存中
4.万事万物皆是对象,class 文件在内存中使用 class 类表示
5.当使用反射的时候,首先需要获取到class 类,得到了这个类之后,就可以得到 class 文件里面的所有内容——包含属性,构造方法,普通方法
6.属性通过一个类 Filed
7.构造方法通过一个类 constructor
8.普通方法通过一个类 Method
使用反射操作类里面的属性
首先获取到Class类
Class clazz1=person.class;
Class clazz2=new person().getClass();
Class clazz3=Class.forName("day06.person");
操作无参数的构造方法
public void test1() throws Exception{
//得到 class
Class c3=Class.forName("cn.itcast.test09.Person");
//得到 person 实例
person p=(person)c3.newInstance();
//设置值
p.setName("zhangsan");
System.out.println(p.getName());
}
使用反射操作有参数的构造方法
public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class c1=Class.forName("cn.itcast.test09.Person");
//传递有参数的构造方法里面的参数类型,类型使用 class 形式传递
Constructor cs=c1.getConstructor(String.class,String.class);
//通过有参数的构造方法设置值
//通过有参数的构造方法创建Person实例
person p1=(person) cs.newInstance("lisi","100");
System.out.println(p1.getId()+" "+p1.getName());
}
使用反射操作属性
public void test3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
try {
Class cc=Class.forName("day06.person");
//得到 person 类的实例
Person p11=(Person) c2.newInstance();
//通过这个方法得到属性,参数是属性的名称
Field f1=cc.getDeclaredField("name");
//操作的是私有属性,不让操作,需要设置可以操作私有属性setAccessible(true)
f1.setAccessible(true);
//设置name的值
f1.set(p , "wangwu");//相当于 p.name="wangwu"
}catch(Exception e) {
e.printStackTrace();
}
}
使用泛型操作普通方法
使用 Method 类表示普通方法
public void test4() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class c4=Class.forName("day06.person");
/ /得到 person 实例
person p4=(person) c4.newInstance();
//得到普通方法
//传递两个参数,第一个参数:方法名称第二个参数:通过方法设置的值
Method m1=c4.getDeclaredMethod("setname", String.class);
//让 setName方法执行,执行设置值
m1.invoke(p4, "niuqi");
System.out.println(p4.getName());
}
操作的私有的方法,需要设置值是true
当操作的方法是静态的方法时候,因为静态方法调用方式是 类名.方法名 不需要类的实例
使用反射操作静态方式时候,也不需要实例
在invokie方法的第一个参数里面 ,写一个 null