自动装箱和拆箱:
装箱:把基本数据类型的数据装箱成对象类型
拆箱:把对象的类型变成基本数据类型
在jdk1.5及以后版本自动装箱和拆箱
int i=10;
Integer ii=i;
int k=ii
在jdk1.5以前的版本
int i=10;
Integer ii=new Integer(10);
int k=ii.intValue();
增强for循环:
for(类型 变量名 : 集合或数组){
}
可变参数:
-用…来定义
-本质就是一个数组
-可以传入任意个参数
-可变参数只能放在方法参数的最后一个位置
静态导入:
-用import static 报名.类名.静态属性名或静态的方法名
-可以提高开发效率
-降低了可读性,建议要慎用
枚举:enum
当取值为几个(有限)固定的值.可以使用枚举类型
枚举是一个数据类型
普通的枚举:
1
2
3 public enum RequestMethod{
GET,POST,DELETE,PUT
}
1
2
3
4
5
6
7
8
9
public enum Week{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
总结:
枚举也可以有方法和属性和构造函数
但是构造方法必须是私有的.
枚举还可以实现接口,不能进行继承,枚举也可以包含抽象方法
所有的枚举的类型都默认继承自java.lang.Enum类
反射
(一)什么是反射:
java中提供一套类库,通过这样的类库
-运行时动态获取类中的信息
-运行时动态的调用构造函数创建对象
-运行时动态访问(调用)对象的方法和属性
这种运行期间动态获取类中的信息(属性,方法,包,注解等)
以及动态的调用对象的方法和属性的功能称之为java语言的反射机制
通俗的理解,在运行期间对类的内容进行操作
(二)Class类:
要想使用反射,就要获取到类中的所有信息(属性,方法,注解等…)
在java中有一个特殊的类 类型是Class,此类型的对象中存储是某个
类中的信息
比如:
Class clazz=Class.forName(“lut.Student”);
clazz是一个对象,对象中存储的都是数据,这些数据
都是Student中的属性和方法
属性:访问修饰符 类型 属性名
方法:访问修饰符 返回类型 方法名称(参数列表);
Class clazz=Class.forName("lut.User");
clazz存储的是User类中的信息 Class类是java提供的,这个Class类可表达任意一个类的信息
-每个类加载后(方法区),系统都会为该类生成一个对应的Class
类型的对象,这个对象存储在堆区中,通过该Class对象可以
访问方法区中的类的信息
-一旦获取了某个类Class类型的对象之后,程序员可以写程序调用
Class对象中的api方法,获取Class对象中的类的信息
-所有的基本数据类型有Class对象
Class clazz=int.class;
(三)如何获取Class类型的对象
-对象.getClass();
比如:
User user=new User();
Class clazz=user.getClass();
-类名.class
比如:
有一个类叫做User类
Class clazz=User.class;
-Class.forName(“包名.类名”);
比如:
Class clazz=Class.forName(“lut.User”);
类的加载分为两个步骤:
-把类加载到方法区中,并创建类的Class类型的对象
-返回Class对象,用以上三种获取Class类型的对象
(四)通过Class类型对象获取如下:
-Field类:代表的成员变量,即属性
-Method类:代表的是方法
-Constructor类:代表的是构造方法
-Annotation类:代表的是注解
通过上面类的api方法获取数据
-可以获取Field类中的信息,获取类的属性 访问修饰符 属性的类型 属性名称
-可以获取Method类中的信息,获取方法 修饰符 返回类型 方法名(参数列表)
-可以获取Constructor中的信息,获取构造函数, 修饰符 类名(参数列表)
-可以获取Annotation中的信息,获取注解 注解名称 注解的属性
结论:
在运行期间,通过Class对象调用反射的api
可以反射实例化对象
可以反射访问属性,和反射调用方法
总之,编译期间能写的代码,用反射也能实现
(五)反射的api:
-反射的方式创建对象
1.用无参数构造创建对象
Class对象.newInstance();//常用的做法
2.用有参数构造创建对象
Class对象.getConstructor(new Class[]{若干参数的类类型})
.newInstance(构造函数的参数);
比如:
//有参数构造
public User(String name,String password){
}
Class clazz=User.class;
//传统的实例化对象
User user=new User(“zhangsan”,”zs”);
//反射的做法:
User user=clazz.getConstructor(new Class[]{String.class,String.class})
.newInstance(“张三”,”zs”);
-反射方式获取Field中的信息
1.获取当前类以及长辈类的public Field
Field[] fields=Class对象.getFields();
2.获取当前类中的所有的属性Field
Field[] fields=Class对象.getDeclaredFields()
3.获取当前类以及长辈类中指定的共有属性
Field field=Class对象.getField(String fieldName);
4.获取当前类中指定的属性
Field field=Class对象.getDeclaredField(String fieldName);
5.通过反射设定Field属性
Field对象.set(Object obj,Object value);
如果Field是私有的
必须先执行:Field对象.setAccessable(true);//设置属性可以访问
6.通过反射获取Field的值
Object value=Field对象.get(object);
如果Field是私有的
必须先执行:Field对象.setAccessable(true);//设置属性可以访问
-反射方式获取Method方法信息
1.获取当前类以及长辈类的public Method
Method[] methods=Class对象.getMethods();
2.获取当前类中的所有的属性Field
Method[] methods=Class对象.getDeclaredMethods()
3.获取当前类以及长辈类中指定的共有属性
Method method=Class对象.getMethod(String methodName,new Class[]{方法参数类型});
4.获取当前类中指定的属性
Method method=Class对象.getDeclaredMethod(String methodName,new Class[]{方法参数类型});
5.通过反射动态调用Method
Object returnValue =Method对象.invoke(Object obj,object…args);
解析:
就是通过obj这个对象,调用Method对象确定的方法,给这个方法传递的参数是args
Method对象对应的方法放回值returnValue;
-反射获取Constructor构造函数
-具体查看api文档
-反射获取注解Annotation
-具体查看api文档
(六)在哪些地方使用反射,反射的应用场景
-用反射实现jdbc的通用查询和通用更新
-用反射解析注解
-单元测设,就是用反射实现的
-常见的框架,spring框架,apringmvc框架等,都是用反射实现的
-EL表达式
等…
反射的优点:
大幅度提高开发效率,框架就是反射实现的,框架可以大大提高开发效率
反射的缺点:
反射执行效率比非反射的方式执行效率低
反射可以暴露类中的所有细节,突破了封装.
内省:
就是自查的意思,本质就是反射,利用反射自省类中的属性和方法和其他
自省的方式有两种
方式一:
jdk(jre)中自带的一套自省的类库,类库包含的是api方法
侧重:属性和属性的值,属性所对应的getter和setter方法
方式二:
apache基金会提供一套公有的自省类库CommonsBeanUtils.jar
他能够处理属性和属性的值和对应的getter和setter
还可以处理普通的方法
总结:
1.能用Commons-Beanutils就用此工具类
2.其次用java的原生的内省Introspector工具类
3.最后用java的原生的反射api Class Field Method Constructor Annotation
原生反射api是最灵活的
要开发快选择1方式
要灵活选择3方式
注解:
- 注解应用场景很广泛,将来是一个趋势
- 他可以提高开发效率,但是执行效率堪忧,因为其底层解析注解是用反射解析的
- 用注解可以替换xml配置和属性文件
- 注解是一个标识,注解所代表的功能一定要用反射来实现
- 这些反射的代码,用于解析(寻找注解,获取注解的属性值)
- 然后根据设定的属性值,来决定是否执行一些业务功能
(一)使用注解有三个步骤:
1.用户定义注解 创建注解
2.把注解应用到对应的目标上 把注解放什么地方(包,类,属性,方法,方法参数等)
3.用反射的代码来确定是否有注解和注解属性值,
根据是否有注解以及注解的值做相应的功能
(二)如何定义注解:
程序员创建注解
1 | //设定MyAnnotation注应用在什么位置上 |
(三)元注解/源注解
@Target和 @Retention和@Override等…都是jdk自带的注解
1.@Target(value={ElementType.Method,…})
指定要修饰在什么样的目标上(包,注解,类/接口,方法,属性,参数等…)
value取值是一个枚举类型的数据
ElementType:
ANNOTATION 注解
METHOD 方法
FIELD 属性
CONSTRUCTOR 构造
TYPE 类/接口
PARAMETER 方法的参数上
等…
2.@Retention(RetentionPolicy.RUNTIME)
注解的保留策略
.java--.class-->jvm执行.class
SOURCE:源代码级别,Source修饰的注解是给编译看的
编译器把源代码编译完毕后,在class文件中就没有注解
CLASSS:类级别,Class修饰的注解给类加载器看的
在类加载的时候可以做一系列的引导操作,
在编译器编译完毕后注解存在,在类加载加载之后
就要丢弃注解
RUNTIME:运行时级别,给JVM看的,在程序运行的过程中做相关的操作
可以在jvm中借助反射api解析注解(四)注解中的属性详解:
a.注解定义属性和接口定义的方法类似,缺省默认public
public 类型 属性名称();
b.定义属性是,如果没有使用default指定默认值
则在使用注解,必须给属性赋值
如果带有默认值,是在使用注解的时候给属性赋值为新值
也可以使用默认值
c.注解中的属性类型必须遵守如下要求
可以是八种基本数据类型,枚举类型,Class类型,String类型,
以及上面类型的一维数组
d.在给数组赋值的时候,如果数组只有一个值就不用写{}
e.有一个极特殊的属性value
如果只为该属性赋值,value=值
但是如果注解中只有value这一个属性,那么value可以省略
(五)把注解应用到目标
在对应的目标上写上注解
1
2
3
4
5
6
7
8
9
10
11
12 @MyAnnotation(value="xx",name="yy",colors={"pink","green","gay"})
public class Demo1 {
private String str;
@MyAnnotation(value="aa",name="bb")
public void method1(String name){
}
public void method2(){
}
}
(六)写反射代码来解析注解:
a.解析类上的注解
b.解析方法上的注解
泛型:
(一) 一种参数化的类型
//非泛型的写法,不是参数化得类型
ArrayList list0=new ArrayList();
list0.add(“abc”);
list0.add(10);
//泛型的标准的写法,标准参数化的类型, 参数化类型指的是可以任意类型
ArrayList
list1.add(“abc”);
list1.add(“aaa”);
//泛型的写法,但不推荐
ArrayList list2=new ArrayList
list2.add(“abc”);
list2.add(“aaa”);
list2.add(10);//语法是可以通过的
//泛型的写法,但不推荐
ArrayList
list3.add(“abc”);
list3.add(“aaa”);
//list3.add(10);//语法是错误的
//下列的写法是错误的,编译报错,泛型要求两端的类型必须一致
//ArrayList<Object> list4=new ArrayList<String>();(二)自定义泛型
类上的泛型,泛型类
1、泛型类一定要先定义,后使用,在类的名字后面定义泛型的类型
2、泛型的类型一定要是引用数据类型,不能是基本数据类型
3、 定义在类上,在类的内部使用,在整个类范围内类型是一致的
4、类上的泛型的具体类型需要在创建类的对象的时候指定泛型具体类
5、如果在使用类上泛型时不指定泛型的具体类型,默认的具体类型为泛型的上边界方法上的泛型,泛型方法
泛型要先定义后使用,在返回类型之前定义,通常用大写字母
来定义一个泛型方法,可以定义多个,且定义在方法上,在方法的内部
使用,方法上泛型,在方法调用的时候自动推断出具体的类型,
无论何时,尽量使用泛型方法,因为泛型方法作用域小,只局限
于方法内部
T :类型type
E :元素element
K :关键字key
V :值 value
…
比如:1
2
3public <T,E> T save(T t,E e){
return t;
}<T,E>就是标记,标记此方法是一个泛型方法放在修饰符和返回
类型之间,可以放置多个符号,说明有多个参数化类型
(三)泛型的上边界:
- 泛型所取得类型是上边界或上边界类型的子孙类型
- 如果不指定泛型默认的上边界是Object
(四)泛型擦除:
泛型编译期间起作用,真正执行期间,泛型已经被擦除了,在编译阶段,编译器会将所有使用泛型的地方替换为泛型的上边界,并在必要的时候增加上必须的类型转换和类型检查,所以在执行期间没有泛型的概念了。泛型在编译期间就被擦除掉了.此过程叫做泛型的擦除
(五)集合与泛型
在 <<Easy Coding>> 一书中是这样解释的:
1、List、List
- <? extends T>
- 是Get First,适用于消费集合元素为主的场景
- 可以赋值给任何T及T子类的集合,上界为T
- 取出来的数据带有泛型限制,向上强制转型为 T ,null 可以表示任何类型,除 null 外,任何元素都不得添加进 <? extends T> 集合内
- <? super T>
- 是Put First ,适用于生产集合元素为主的场景
- 可以赋值给任何T及T父类的集合,下界为T
- 只能往里放数据,而在取数据时不知道该数据具体属于谁,相当于泛型丢失
extends 的场景是 put 功能受限,而 supper 的场景是 get 功能受限。
* 书中所举例子,以加菲猫、猫、动物为例,说明extends 和 super 的详细语法差异,源代码如下:
1 | //用动物的猫科与加菲猫的继承关系说明 extends 与 super 在集合中的意义 |

