- 自动拆箱和装箱
- 增强for循环
- 枚举(enum)
- 反射
- 反射方式创建对象
- 反射方式获取Filed中的信息
- 反射方式获取Method方法的信息
- 反射获取Construction构造函数
- 反射获取Annotation注解
- 反射应用场景
- 反射的优点:
- 反射的缺点:
- 理解题目
- 反射例子
- 内省:
- 注解
- 泛型
jdk1.5新特性:
自动拆箱和装箱
增强for循环
可变参数:
- 用…来定义
- 本质是一个数组
- 可以传入任意个参数
- 可变参数只能放在方法参数的最后一个位置
静态导入
- 用import static 包名.类名.静态属性名或静态方法名
- 可以提高加载效率
- 降低了可读性,建议慎用
枚举(enum)
当取值为几个(有限)固定的值,可以使用枚举类型
枚举是一个数据类型
普通的枚举
public enum requestMethod{
GET,POST,DELETE,PUT
}
public enum Week{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
枚举也可以有方法和属性和构造方法,但是构造方法必须是私有的
枚举还可以实现接口,不能继承,枚举也可以包含抽象方法
所有自定义的枚举都默认继承自java.lang.Enum类
String name();
int ordinal();
反射
java中的提供的一套类库,通过这套类库可以
- 运行时动态获取类中的信息
- 运行时动态的调用构造函数,创建对象
- 运行时动态的访问(调用)对象的方法和属性
这种运行期间动态获取类中的信息(属性,方法,包,注解等),以及动态调用对象的方法和属性的功能称为java的反射机制
通俗理解:在运行期间,对类的内容进行操作
Class类
要想使用反射,就要获取到类中的所有信息(属性,方法等…)
在java中,有一个特殊的类类型是Class,此类型的对象中存储的是某个类中的信息
比如:
Class clazz1 = Class.forName(“cn.tedu.Student”);
clazz1是一个对象,此对象中存储的都是数据,这些数据都是Student中的属性和方法
属性:访问修饰符,类型,属性名
方法:访问修饰符,返回类型,方法名(参数列表)
Class Clazz2 = Class.forName(“cn.tedu.User”);
Clazz2也是一个对象,对象中存储的是User类中的属性和方法
Class类是java提供的,这个Class类可以表达任意一个类的信息(属性,方法等类中的信息)
- 每个类加载后(方法区),系统都会为该类生成一个对应的Class类类型的对象,这个对象是存储在堆区中,通过该Class对象,可以访问方法区类中的信息
- 一旦获取了某个类Class类型的对象之后,程序员可以写程序调用Class对象中的api方法,获取给Class对象中的类的信息
- 所有的基本数据类型也有Class对象
如何获取Class类型的对象
- 对象.getClass();
比如
User user=new User();
Class clazz1 = user.getClass(); - 类名.Class
比如
有一个类是User类型
Class clazz = User.class; - Class.forName(“包名.类名”);
比如
Class clazz1 = Class.forName(“cn.miralce.User”)
此种情况分为两步- 加载类User,进方法区,创建Class类型的对象
- 把返回Class类型的对象
public void testMethod1(){
//传统做法,在编译期间确定调用的关系
User user = new User();
user.setUserName("张三");
user.setUserPassword("zs");
System.out.println(user.getUserName()+user.getUserPassword());
}
//反射的做法,首要要得到Class类型的对象
//此对象,在类加载后自动有jvm创建,并把对象放在堆中
//程序员只是通过api获取Class对象
public void testMethod2()throws Exception{
//方式一
User user = new User();
Class clazz1 = user.getClass();
//方式二
Class clazz2 = User.class;
//方式三
Class clazz3 = Class.forName("cn.tedu.day20.reflect.User");
//输出
}
用以上的三种方式,可以获取到Class类型的对象
通过Class类型的对象获取如下:
- Filed类
代表成员变量,即属性 - Method类
代表方法 - Constructor类
代表构造函数 - Annotation类
代表注解
通过上面的类的api获取对应的信息
- 可以获取Field中的信息,获取类的属性,属性的修饰符,属性的类型,属性的名称
- 可以获取Method中的信息,获取类的方法,修饰符,返回类型,方法名,参数列表
- 可以获取Constructor中的信息,获取构造函数,修饰符,参数列表
- 可以获取Annotation中的信息,获取注解,获取注解的名称,注解属性值
结论:在运行期间,通过Class对象调用反射的api,可以反射实例化对象,可以反射访问属性和反射调用方法,总之,编译期间能写的代码,用反射也能实现. —
下面例子用到的User.java类
import java.util.Date;
public class User {
private String userName;
private String userPassword;
String userAddress;
protected int age;
public String desc;
public int weight;
public User(){}
public User(String userName, String userPassword){
this.userName = userName;
this.userPassword = userPassword;
}
public User(String userName, String userPassword, String userAddress, int age, String desc) {
this.userName = userName;
this.userPassword = userPassword;
this.userAddress = userAddress;
this.age = age;
this.desc = desc;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
private float xxx(int a,float b){
return 0f;
}
protected void yyy(String a,double b){
}
String zzz(String a, Date data){
return null;
}
}
反射方式创建对象
- 用无参数构造创建对象
Class对象.new Instance();//常用
/**
* 创建对象
* 方式一 调用无参数构造实例化对象
* @throws Exception
*/
public void testMethod5_1() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Object obj = clazz.newInstance();
}
- 用有参构造创建对象
Class对象.getConstructor(new Class[]{若干参数的类类型}).newInstance(构造函数的参数);
/**
* 调用有参构造
* @throws Exception
*/
public void testMethod5_2() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
//获取构造函数
Constructor constructor = clazz.getConstructor(String.class,String.class);
// Constructor constructor = clazz.getConstructor(new Class[]{String.class,String.class});
Object obj = constructor.newInstance("张三","zs");
Field field1 = clazz.getDeclaredField("userName");
Field field2 = clazz.getDeclaredField("userPassword");
field1.setAccessible(true);
field2.setAccessible(true);
System.out.println("userName="+field1.get(obj));
System.out.println("userPassword="+field2.get(obj));
}
反射方式获取Filed中的信息
- 获取当前类以及长辈类的公有属性
Field[] field = Class对象.getFields();
/**
* 从Class对象中获取Field
* 当前类以及长辈类中的公有属性
* @throws Exception
*/
public void testMethod4_1()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field[] fields = clazz.getFields();
for(Field field:fields){
System.out.print(field.getModifiers()+" ");//返回值是int,int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
}
}
- 获取当前类的类中所有的属性
Field[] fields = Class对象.getDeclaredFields();
/**
* 从Class对象中获取Field
* 当前类中的所有属性
* @throws Exception
*/
public static void testMethod4_2() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields){
System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
}
}
- 获取当前类以及长辈类中指定的公有属性
Field field = Class.对象.getField(String fieldName);
/**
* 当前类以及长辈类的指定的公有属性
* @throws Exception
*/
public static void testMethod4_3()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field field = clazz.getField("desc");
System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
}
- 获取当前类中指定的属性
Field field = Class.对象.getDeclaredField(String fieldName);
/**
* 当前类中的指定的属性
* @throws Exception
*/
public static void testMethod4_4() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field field = clazz.getDeclaredField("userName");
System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
}
- 通过反射设定Field属性的值
Field对象.set(Object obj,Object value);
如果Field是私有,必须先执行:Field对象.setAccessable(true);//设置属性可以访问
/**
* 给Field存值
* @throws Exception
*/
public static void testMethod4_5() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field field = clazz.getDeclaredField("userName");
System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
//创建对象
Object obj = clazz.newInstance();
//设置Field的可访问性
field.setAccessible(true);
//给Field存储数据
field.set(obj,"zhangsan");
if(obj instanceof User){
User user = (User)obj;
System.out.println(user);
}
}
- 通过反射动态获取Field的值
Object value = Field对象.get(Object obj);
如果Field是私有,必须先执行:Field对象.setAccessable(true);//设置属性可以访问
/**
* 给Field存值取值
* @throws Exception
*/
public static void testMethod4_6() throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Field field = clazz.getDeclaredField("userName");
System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
System.out.print(field.getType()+" ");
System.out.println(field.getName());
//创建对象
Object obj = clazz.newInstance();
//设置Field的可访问性
field.setAccessible(true);
//给Field存储数据
field.set(obj,"zhangsan");
//从Field中取出数据
Object value = field.get(obj);
System.out.println(value);
}
反射方式获取Method方法的信息
- 获取当前类以及长辈类的公有方法
Method[] method = Class对象.getMethods();
/**
* 从Class中取出Method方法
* 从当前类及其长辈类中获取的所有的公有方法
* @throws Exception
*/
public static void testMethod6_1()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Method[] methods = clazz.getMethods();
for(Method method:methods){
System.out.print(method.getModifiers()+" ");//获取访问修饰符
System.out.print(method.getReturnType()+" ");//获取返回类型
System.out.println(method.getName()+"(");//获取方法名称
//获取参数列表
Class[] claxxs = method.getParameterTypes();
if(claxxs!=null&&claxxs.length>0){
for(int i = 0;i<claxxs.length-1;i++){
System.out.print(claxxs[i]+",");
}
System.out.println(claxxs[claxxs.length-1]);
}
System.out.println(")");
}
}
- 获取当前类中的所有的方法
Method[] method = Class对象.getDeclaredMethods();
/**
* 从Class中取出Method方法
* 从当前类中获取的所有的方法
* @throws Exception
*/
public static void testMethod6_2()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Method[] methods = clazz.getDeclaredMethods();
for(Method method:methods){
System.out.print(method.getModifiers()+" ");//获取访问修饰符
System.out.print(method.getReturnType()+" ");//获取返回类型
System.out.println(method.getName()+"(");//获取方法名称
//获取参数列表
Class[] claxxs = method.getParameterTypes();
if(claxxs!=null&&claxxs.length>0){
for(int i = 0;i<claxxs.length-1;i++){
System.out.print(claxxs[i]+",");
}
System.out.println(claxxs[claxxs.length-1]);
}
System.out.println(")");//为了防止最后一个有逗号
}
}
- 获取当前类以及长辈类中的指定的公有的方法
Method method = Class对象.getMethod(String methodName,new Class[]{methodName的参数类型});
/**
* 从Class中取出Method方法
* 从当前类及其长辈类中获取指定的公有方法
* @throws Exception
*/
public static void testMethod6_3()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Method method = clazz.getMethod("setUserName",String.class);
System.out.print(method.getModifiers()+" ");//获取访问修饰符
System.out.print(method.getReturnType()+" ");//获取返回类型
System.out.print(method.getName()+"(");//获取方法名称
//获取参数列表
Class[] claxxs = method.getParameterTypes();
if(claxxs!=null&&claxxs.length>0){
for(int i = 0;i<claxxs.length-1;i++){
System.out.print(claxxs[i]+",");
}
System.out.print(claxxs[claxxs.length-1]);
}
System.out.println(")");
}
- 获取当前类中的指定的方法
Method method = Class对象.getDeclaredMethod(String methodName,new Class[]{methodName的参数类型});
/**
* 从Class中取出Method方法
* 从当前类中获取指定的方法
* @throws Exception
*/
public static void testMethod6_4()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Method method = clazz.getDeclaredMethod("xxx" ,int.class,float.class);
System.out.print(method.getModifiers()+" ");//获取访问修饰符
System.out.print(method.getReturnType()+" ");//获取返回类型
System.out.print(method.getName()+"(");//获取方法名称
//获取参数列表
Class[] claxxs = method.getParameterTypes();
if(claxxs!=null&&claxxs.length>0){
for(int i = 0;i<claxxs.length-1;i++){
System.out.print(claxxs[i]+",");
}
System.out.print(claxxs[claxxs.length-1]);
}
System.out.println(")");
}
- 通过反射动态调用指定的Method
Object returnValue = Method对象.invoke(Object obj,Object…args);
解释:Method对象是确定的方法,给这个方法传递args参数,没有参数就不传,obj是实例化对象
返回值是基本类型的封装类,比如int类型会装箱为Integer.
public void testMethod6_5()throws Exception{
//传统方式
User user = new User();
user.setUserName("张三");
user.getUserName();
//反射的方式
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Object obj = clazz.newInstance();
Method method = clazz.getMethod("setUserName",String.class);
Object returnValue = method.invoke(obj,"张三");
Method Method = clazz.getMethod("getUserName")
Object returnValue = method.invoke(obj);
}
反射获取Construction构造函数
/**
* 遍历所有的构造,用反射方式
* @throws Exception
*/
public void testMethod7_1()throws Exception{
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
Constructor[] cons = clazz.getDeclaredConstructors();
for (Constructor con:cons){
System.out.print(con.getModifiers()+" ");//访问修饰符
System.out.print(con.getName()+"(");//构造函数的名字
//获取构造的参数类型
Class[] claxxs = con.getParameterTypes();
if(claxxs!=null&&claxxs.length>0){
for (int i = 0; i < claxxs.length-1; i++) {
System.out.print(claxxs[i]+",");
}
System.out.print(claxxs[claxxs.length-1]);
}
System.out.println(")");
}
}
反射获取Annotation注解
略
反射应用场景
- 用反射实现jdbc通用的查询和通用更新
- 用反射解析注解
- 单元测试就是用反射实现
- 常见的框架.spring框架,springmvc框架等都是用反射实现
- EL表达式
…
反射的优点:
大幅度提高开发效率,框架就是用反射实现的,框架提高了开发效率
反射的缺点:
反射的执行效率比非反射的方式效率低
反射可以暴露类中的所有细节,突破了封装
理解题目
通过Method对象可以获取方法的信息 访问修饰符 返回数据类型 方法名称(参数列表的类型)
通过Method对象还可以调用方法,用反射的方式,可以调用任意方法
Object returnValue = Method对象.invoke(调用方法的对象名,方法参数);//可以调用任意方法,通用的方法调用
需求:
给一个对象中的私有数据赋值
实现方案一:传统的静态的方式,在编译期间确定好的调用关系
对象名.setXXX(参数);
实现方案二:用反射的方式调用setXXX方法,在运行期间才能确定调用此方法
setMethod()
/**
* 通用的存储数据的方法,主要目的是为了要演示反射调用方法invoke
* 演示反射能做出通用的功能,提高了开发效率
* @param propertyName 属性名称
* @param obj 对象名
* @param args 方法参数
* 分析步骤:
* 1.获取Class对象
* 2.根据属性的名称构建一个方法名(骆驼命名法)
* 3.通过class对象反射获取所有的方法
* 4.遍历所有的方法,匹配第二部的方法名
* 5.如果匹配到就调用
* 结论: 在运行期间根据原则寻找方法,如果找到方法就调用,不是在编译期间调用的
*/
private void setMethod(String propertyName,Object obj,Object...args)throws Exception{
//获取Class对象
Class clazz = obj.getClass();
//set+U+serName == setUserName
String setterName = "set"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
//根据Class对象反射出类中的所有的方法
/* Method[] methods = clazz.getDeclaredMethods();
//循环遍历
for(Method method:methods){
//寻找类中是否有对应的set方法
if(setterName.equals(method.getName())){
method.setAccessible(true);//保证方法能够被访问
method.invoke(obj,args);
}
}*/
Field field = clazz.getDeclaredField(propertyName);//循环效率低,直接通过参数来得到类型
Method method = clazz.getDeclaredMethod(setterName,field.getType());
method.setAccessible(true);
method.invoke(obj,args);
}
getMethod()
/**
* 通用取值的方式
* @param propertyName 属性名称
* @param obj 调用方法的对象名
* @return 方法的返回值
* 分析:
* 1.获取Class对象
* 2.根据属性名称拼装一个get方法的名称
* 把属性名第一个字母大写,前面加上get
* 3.根据Class对象反射出类中的所有的方法
* 4.遍历所有的方法,匹配第二步的方法名称
* 5.如果匹配就调用getter方法,并把值返回
*
*/
private Object getMethod(String propertyName,Object obj)throws Exception{
Object returnValue = null;
//获取Class对象
Class clazz = obj.getClass();
//拼装方法名称
String getterMethod = "get"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
/* //根据Class对象反射出所有的方法
Method[] methods = clazz.getDeclaredMethods();
//循环遍历所有的方法,匹配方法名称
for (Method method:methods){
if(getterMethod.equals(method.getName())){
method.setAccessible(true);
returnValue = method.invoke(obj);
}
}*/
Method method = clazz.getDeclaredMethod(getterMethod);
method.setAccessible(true);
returnValue = method.invoke(obj);
return returnValue;
}
调用上面两个方法为user赋值
public void testMethod6_6()throws Exception{
//反射方式
Class clazz = Class.forName("cn.tedu.day21.reflect.User");
//反射的方式获取创建对象
Object obj = clazz.newInstance();
//通用set方法
setMethod("userName",obj,"张三");
setMethod("age",obj,20);
setMethod("userPassword",obj,"zs");
//通用get方法
Object username = getMethod("userName",obj);
Object userpassword = getMethod("userPassword",obj);
Object userage = getMethod("age",obj);
System.out.println(userage+" "+username+" "+userpassword);
}
反射例子
PropertyUtil.java
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 此类专门用来解析.properties文件的
*/
public class PropertyUtil {
//java.util.Properties类专门用来存储key和value的数据
//key和value是存储在.properties文件中
//有人把java.util.Properties类当成集合看待
private Properties p = new Properties();
public PropertyUtil(String fileName){
//把指定的属性文件中的key和value装载到p对象中
//1.获取属性文件的输入流
InputStream is = PropertyUtil.class//Class类型的对象
.getClassLoader()//返回类的类加载器,变相的得到类路径
.getResourceAsStream(fileName);//从类路径下寻找fileName的文件
//2.把is输入流对象中的数据加载给p对象
try {
p.load(is);
} catch (IOException e) {
e.printStackTrace();
}
}
//根据key的值,从p中取出key所对应的value.并返回
public String getPropertyValue(String key){
return p.getProperty(key);
}
}
Product.java
package cn.tedu.day21.reflect;
public class Product {
private int id;
private String name;
private double price;
private int num;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
test.java
public void test throws Exception{
PropertyUtil pu = new PropertyUtil("resource/classname.properties");
Object obj = Factory.getObject(pu.getPropertyValue("user"));
System.out.println(obj.getClass());
}
classname.properties
#这是一个属性文件key=value,不能有空格和空行
user=cn.tedu.day21.reflect.User
product=cn.tedu.day21.reflect.Product
内省:
自查,本质是反射,利用反射自省类中的属性,方法和属性
自省的实现方式有两种
1. jdk(jre)中自带的一套自省的类库
类库中包含的是api方法,侧重属性和属性的值,以及属性所对象的getter和setter方法
例子
User.java
public class User {
private String userName;
private String userPassword;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
TestIntrospectorClass.Java
public class TestJdkIntrospectorClass {
/**
* 演示获取BeanInfo对象
* @throws Exception
*/
public void testMethod1()throws Exception{
Class clazz = User.class;
//通过自省类获取类中的所有的信息(底层还是反射)
// 把反射出来的信息封装BeanInfo
BeanInfo bi = Introspector.getBeanInfo(clazz);
//原来使用反射的api操作类中的信息
//用自省的BeanInfo中的api来操作类中的信息
}
/**
* 内省指定的bean类中的属性信息
* 然后根据属性信息获取属性的getter方法和setter方法
* @throws Exception
*/
public void testMethod2()throws Exception{
User user = new User();
//获取bean类中的信息
BeanInfo bi = Introspector.getBeanInfo(user.getClass());
//解析BeanInfo类的对象,能解析出属性和方法
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
//遍历所有的属性描述器,每一个属性描述器代表一个属性Field
for(PropertyDescriptor pd:pds){
Method writeMethod = pd.getWriteMethod();
if(writeMethod!=null){
writeMethod.invoke(user,"zhangsan");
}
Method readMethod = pd.getReadMethod();
if(readMethod!=null){
Object returnValue = readMethod.invoke(user);
System.out.println(returnValue);
}
}
}
public void testMethod3()throws Exception{
User user = new User();
//获取指定属性的setter方法
// 获取指定属性的getter方法
PropertyDescriptor pd = new PropertyDescriptor("userName",User.class);
Method getReadMethod = pd.getReadMethod();
Method getWriteMethod = pd.getWriteMethod();
String propertyname = pd.getName();
Object value = pd.getValue(propertyname);
}
public static void main(String[] args) {
TestJdkIntrospectorClass testJdkIntrospectorClass = new TestJdkIntrospectorClass();
}
}
- Apache基金会提供的一套公共的自省类库Commons-BeanUtils.jar
commons-BeanUtils工具,此工具中包含若干工具
- MethodUtils工具类
- ConstructorUtils工具类
- PropertyUtils工具类
例子
User.java
public class User {
private String userName;
private String userPassword;
public User(String userName, String userPassword) {
this.userName = userName;
this.userPassword = userPassword;
}
public User(){}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
TestBeanUtilsClass.java
public class TestBeanUtilsClass {
/**
* 演示MethodUtils工具类
*/
public void testMethod1()throws Exception{
User user = new User();
//用MethodUtils的api查找方法
Method method = MethodUtils.getAccessibleMethod(User.class,"setUserName",String.class);
//找到方法就可以调用方法
if (method!=null){
Object returnValue = method.invoke(user,"zhangsan");
}
//查找到了就直接调用
Object returnValue = MethodUtils.invokeMethod(user,"setUserName","zhangsan");
Object value = MethodUtils.invokeMethod(user,"getUserName",null);
System.out.println(returnValue+" "+user.getUserName()+" "+value);
}
/**
* 演示ConstructorUtils工具类
*/
public void testMethod2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
//用ConstructorUtils方式查找构造函数
Constructor<User> constructor = ConstructorUtils.getAccessibleConstructor(User.class,new Class[]{String.class,String.class});
User user = constructor.newInstance("张三","zs");
//用ConstructorUtils方式查找构造函数后直接实例化对象
User user1 = ConstructorUtils.invokeConstructor(User.class,new Object[]{"wangwu","ww"});
}
/**
* 演示PropertyUtils工具类工具类
*/
public void testMethod3() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
User user1 = new User("zhangsan","zs");
User user2 = new User();
//复制属性的值
PropertyUtils.copyProperties(user2,user1);
System.out.println(user2.getUserName()+" "+user2.getUserPassword());
//设置属性的值
PropertyUtils.setProperty(user2,"userName","haha");
}
public static void main(String[] args) throws Exception {
TestBeanUtilsClass t = new TestBeanUtilsClass();
t.testMethod3();
}
}
注解
从JDK5.0开始, Java增加了对元数据(MetaData)的支持,也就是 Annotation(注解)。 Annotation其实就是代码里的特殊标记,它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
使用注解的步骤
1.如何定义注解。 2.把注解应用到对应的目标上 3.通过反射的api,反射注解,并根据反射的注解信息, 决定如何去运行类
1.如何定义注解。
元注解详解:
- @Target(ElementType.METHOD):被修饰的注解能够在什么地方使用
(注解、类/接口、字段、方法、构造方法、参数上..)上面使用。
ElementType: - ANNOTATION_TYPE 注解类型声明
- CONSTRUCTOR 构造方法声明
- FIELD字段声明(包括枚举常量)
- LOCAL_VARIABLE局部变量声明
- METHOD 方法声明
- PACKAGE 包声明
- PARAMETER 参数声明
-
TYPE 类、接口(包括注释类型)或枚举声明
- @Retention(RetentionPolicy.RUNTIME)
- 被它修饰的注解保留域。 编译器 类加载器 JVM
- .java-> .class->加载->运行
- SOURCE:源码级别,给编译器看的,编译完之后直接丢弃该种策略的注解。
- 生成的.class字节码文件中没有该类型的注解
- CLASS:给类加载器看的,在类加载时可以做一系列引导操作。编译器编译后存在,类加载器加载完之后,丢弃该保留域的注解。
- RUNTIME: 给JVM看的,在程序运行的过程中做相关的操作。编译器编译后保留,类加载器加载后保留,在JVM运行时通过反射技术反射使用的是什么注解,注解属性的值是什么,根据他们两个的值做对应的操作。
- @Documented: 自定义的注解如果使用Documented注解,生成的doc文档上,使用该自定义注解的地方会显示注解信息;如果去掉@Documented,生成的doc文档上将不再有注解信息。 注解中的属性详解
- a.注解定义属性和接口中定义方法类似,缺省默认是public。
public 类型 属性名称(); - b.定义属性时,如果没有使用default指定默认值, 使用当前注解必须为该属性赋值(可以利用该特点,设置必须赋值的属性不要使用default指定默认值)。 使用default指定默认之后,该属性在注解使用时可以赋值,也可以不赋值。
- c.注解中的属性类型是有要求的, 可以是八种基本数据类型,可以是枚举类型、Class类型、String等,以及以上类型的“一维”数组 比如:String[] likes() default {}; 在注解使用时,如果数组类型的属性的值是一个值得话,赋值时可以把“{}”省略掉。@Anno1(name=”zs”,likes=”fb”)
- d.存在一个特殊的属性:value, 如果只为该属性赋值,value=可以省略; 但是如果为注解中多个属性同时赋值的话, value=是不可以省
2.把注解应用到对应的目标上
在对应的目标写
@注解的名称(属性名=属性值)
@注解的名称(属性名1=属性值1,属性名2=属性值2,….属性名n=属性值n)
3. 反射注解(注解的运行原理)
参见项目代码
MyAnnotation.java(注解)
//代表此注解可以修饰的目标
@Target({ElementType.TYPE,ElementType.METHOD})
//此注解保留策略,在运行期间能使用此注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//在注解中可以放置注解的属性,注解不是方法
public String value()default "";
public String name() default "abc";
public String[] colors() default {"red","blue"};
}
Demo1.java
/**
* 需求:
* 如果方法上修饰了@MyAnnotation注解,且value的值为xxx,则调用此方法
* 需求2:
* 如果方法上修饰了@MyAnnotation注解,且name的值为bcd,则调用此方法
*/
@MyAnnotation(value = "aaa",name="bbb",colors = {"green","pink"})
public class Demo1 {
private String xxx;
@MyAnnotation(value = "abc",name="bcd",colors={"red","blue"})
public void method1(){
System.out.println("method1");
}
@MyAnnotation("xxx")
public void method2(){
System.out.println("method2");
}
@MyAnnotation("yyy")
public void method3(){
System.out.println("method3");
}
}
TestAnnotationClass.java
public class TestAnnotationClass {
/**
* 此测试方法专门用来解析类上是否有注解,且获取类上的注解的属性值
* 可以根据属性的值来决定如何运行程序
*/
public void testMethod1()throws Exception{
Class clazz = Class.forName("cn.tedu.day22.jdk5.annotation.Demo1");
//查找并判断类上是否有指定的注解
boolean flag = clazz.isAnnotationPresent(MyAnnotation.class);
if(flag){
//说明类上有@MyAnnotation注解
//获取注解的对象
MyAnnotation myAnnotation = (MyAnnotation)clazz.getAnnotation(MyAnnotation.class);
//通过注解的对象获取注解对象中的属性的值
String value = myAnnotation.value();
String name = myAnnotation.name();
String[] colors = myAnnotation.colors();
System.out.println(value);
System.out.println(name);
System.out.println(colors[0]+colors[1]);
//根据value的值,根据name的值,根据colors的值,写if来决定运行哪些代码
if("aaa".equals(value)&&"bbb".equals(name)){
System.out.println("doSomething");
}
}
}
/**
* 解析方法上的注解,然后根据指定的值,决定是否调用方法
*/
public void testMethod2()throws Exception{
Class clazz = Class.forName("cn.tedu.day22.jdk5.annotation.Demo1");
//new对象,有对象,才可以调用方法
Object obj = clazz.newInstance();
//过去类中的所有方法
Method[] methods = clazz.getDeclaredMethods();
for(Method method:methods){
//判断方法上是否有注解
boolean flag = method.isAnnotationPresent(MyAnnotation.class);
if(flag){
//说明方法上有@MyAnnotation注解
//获取方法上的注解的对象
MyAnnotation myAnnotation = (MyAnnotation)method.getDeclaredAnnotation(MyAnnotation.class);
//从注解对象中获取属性的数据
String value = myAnnotation.value();
String name = myAnnotation.name();
String[] colors = myAnnotation.colors();
if("xxx".equals(value)||"bcd".equals(name)){
method.invoke(obj);
}
}
}
}
public static void main(String[] args) throws Exception {
TestAnnotationClass testAnnotationClass = new TestAnnotationClass();
testAnnotationClass.testMethod2();
}
}
总结:用注解就是根据注解和注解上的属性值,来决定是否做一些事 可以是指行指定的功能,也可以是调用一个具体方法
泛型
一种参数化的类型
public static void main(String[] args) {
//非泛型,不是参数化类型
ArrayList list0 = new ArrayList();
list0.add("abc");
list0.add(10);
//泛型标准做法,参数化类型,参数是String类型
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");
list1.add("bcd");
//泛型,不推荐
ArrayList list2 = new ArrayList<String>();
list2.add("abc");
list2.add("bcd");
// list2.add(10);
new Demo1().xxx(list2);
//泛型,不推荐
ArrayList<String> list3 = new Demo1().yyy();
list3.add("abc");
list3.add("bcd");
//下列的做法是错误的做法,编译报错,两端的泛型必须一致
//ArrayList<Object> list4 = new ArrayList<String>();
}
/**
* 此方法模拟jdk1.5之前的方法
*/
public void xxx(List list){
}
/**
* 此方法模拟jdk1.5之前的方法
*/
public ArrayList yyy(){
return new ArrayList();
}
类上的泛型,泛型类
泛型一定要先定义,后使用,在类的名字后面定义
泛型的类型一定要引用数据类型,不能是基本数据类型
不能对确切的泛型类型使用instanceof关键字
比如
if(num instanceof Generic
class Dog extends Animal{}
class Person extends Animal{}
class Animal{}
/**
* T : type 类型
* E : Element 元素
* K : Key 键
* V : value 值
* 程序员可以自定义
*/
public class Doctor<T extends Animal> {
/**
* 此方法不是泛型方法,只是普通的方法
* @param t
*/
public T save(T t){
System.out.println("救治"+t);
return t;
}
public static void main(String[] args) {
//演示泛型类
//医生只能救治dog
Doctor<Dog> doctor1 = new Doctor<Dog>();
doctor1.save(new Dog());
//医生可以救治任何对象
Doctor doctor2 = new Doctor();
doctor1.save(new Dog());
//医生只能救治person
Doctor<Person> doctor3 = new Doctor<Person>();
doctor3.save(new Person());
}
}
方法上的泛型,泛型方法
泛型要先定义后使用
在返回值之前定义,通常用一个大写字母来定义一个泛型,可以定义多个,且定义在方法上,在方法内部起作用,方法上的泛型,在方法被调用的时候自动推断出具体的泛型,无论何时,尽量使用泛型方法,因为作用域小,只局限于方法.
比如:
public