反射与注解与枚举

反射

什么是反射

	JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的法的功能称为java语言的反射机制。 

反射的作用

	通过java语言中的反射机制可以操作字节码文件 (可以读和修改字节码文件)
	通过反射机制可以操作代码片段。(class文件)

Class对象

简称:类对象
注意:一个类只有一个类对象,是在JVM加载该类时生成的
如何获取类对象:
	方式1:使用类名获取
	方式2:使用对象名获取
	方式3:使用Class类提供的静态方法forName方法获取
方式备注
类名.class通过类名进行获取
对象名.getClass()使用对象进行获取
Class.forName(“完整路径,带包名”)通过Class的静态方法获取

类对象常用方法

类对象信息相关
getPackage():获取该类的包对象
	getName():获取包名
getName():获取该类的类名,注意包名+类名
getSimpleName():只获取类名
getSuperclass():获取其父类的类对象
getInterfaces():获取该类的所有实现的接口的类对象

使用方法:
package com.fs.demo01;

import java.io.Serializable;

public class Demo01 implements Serializable{

	public static void main(String[] args) {
		//获取本类的类对象
		Class cls=Demo01.class;
		//获取包对象
		Package pac=cls.getPackage();
		//通过包对象获取包名
		String pacName=pac.getName();
		System.out.println(pacName);
		//获取类对象的类的完整类名,包含包路径
		String enClsName=cls.getName();
		System.out.println(enClsName);
		//只获取类名
		String clsName=cls.getSimpleName();
		System.out.println(clsName);
		//获取父类对象
		Class superName=cls.getSuperclass();
		System.out.println(superName.getSimpleName());
		//获取该类所实现的接口的类对象,因为一个类可实现多个接口因此获取得到的接口类对象为数组
		Class[] interfaces = cls.getInterfaces();
		//foreach打印接口类对象的完整类名
		for (Class c : interfaces) {
			System.out.println(c.getName());
		}
	}

}

输出结果为:
    com.fs.demo01
    com.fs.demo01.Demo01
    Demo01
    Object
    java.io.Serializable

类对象属性相关
getFields():获取所有公共属性
getDeclaredFields():获取所有属性
getDeclaredField("属性名"):获取指定属性
	Field:属性对应的类
        属性对象.get(对象名):获取该对象的该属性
        属性对象.set(对象名,属性值):设置属性值
        属性对象.setAccessible(true):设置属性略过访问权限修饰符限制
        
        
实例:
package com.fs.demo01;

public class Person {
	public String name;
	public String sex;
	private int age;
	public Person() {
		super();
	}
	
	public Person(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}

}

package com.fs.demo01;

import java.io.Serializable;
import java.lang.reflect.Field;

public class Demo2 implements Serializable{

	
	public static void main(String[] args) throws Exception {
		//获取本类的类对象
		Class cls=Class.forName("com.fs.demo01.Person");
		Person person = new Person("张三", "男",18);
		System.out.println(person);
		//获取类对象所在类的所有公共属性,包含其继承的父类的公共属性
		Field[] fields = cls.getFields();
		System.out.println("getFields().getName()获取到的公共属性的名称:");
		for (Field field : fields) {
			System.out.println(field.getName());
		}
		//通过向getField()传入属性名称,获取该属性的Field对象,只能是公共属性
		Field sexField = cls.getField("sex");
		System.out.println("getField(属性名).getName()获取得到属性对象的属性名:");
		System.out.println(sexField.getName());
		//通过Field对象的set方法更改具体对象中属性的值
		sexField.set(person, "女");
		System.out.println("getField(属性名).set()更改对象的属性值:");
		System.out.println(person);
		//获取所有属性,不包含继承得到的属性
		Field[] decl = cls.getDeclaredFields();
		System.out.println(".getDeclaredFields(属性名).getName()得到所有属性:");
		for (Field field : decl) {
			System.out.println(field.getName());
		}
		//通过属性名获取指定属性的对象,可获取得到私有属性的对象
		Field declAge = cls.getDeclaredField("age");
		System.out.println("getDeclaredField(属性名).getName()获取得到属性对象的属性名:");
		System.out.println(declAge.getName());
		//属性对象.setAccessible(true):设置属性略过访问权限修饰符限制
		declAge.setAccessible(true);
		//属性对象.get(对象名):获取该对象的该属性
		System.out.println("getDeclaredField(属性名).get(对象名)获取对象的属性值:");
		System.out.println(declAge.get(person));	
		//属性对象.set(对象名,属性值):设置属性值
		declAge.set(person, 28);
		System.out.println("getDeclaredField(属性名).set()更改对象的属性值:");
		System.out.println(person);

	}

}


输出:
Person [name=张三, sex=, age=18]
getFields().getName()获取到的公共属性的名称:
name
sex
getField(属性名).getName()获取得到属性对象的属性名:
sex
getField(属性名).set()更改对象的属性值:
Person [name=张三, sex=, age=18]
.getDeclaredFields(属性名).getName()得到所有属性:
name
sex
age
getDeclaredField(属性名).getName()获取得到属性对象的属性名:
age
getDeclaredField(属性名).get(对象名)获取对象的属性值:
18
getDeclaredField(属性名).set()更改对象的属性值:
Person [name=张三, sex=, age=28]
类对象方法相关
getMethods():获取所有公共方法的对象,数组
getMethod(name,Class<?>... parameterTypes)通过方法名获取类中方法的对象,仅限公共方法
    name:方法名称	parameterTypes:形参列表的数据类型的类对象,若方法没有形参列表则可省略
getDeclaredMethods():获取所有方法
getDeclaredMethod(name,Class... types):获取指定的方法
    name:方法名
	types:该方法的形参列表对应的类对象
Method(方法对应的类):
	方法对象.setAccessible(true):设置属性略过访问权限修饰符限制
	方法对象.invoke(对象名,实参列表):调用方法
       
实例:
具体类:
public class Person {
	public String name;
	public String sex;
	private int age;
	public Person() {
		super();
	}
	
	public Person(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	private void pfun(String act) {
		System.out.println("这是一个私有方法,你可通过该方法进行"+act);
	}
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
	
}

方法实现:
import java.lang.reflect.Method;

public class Demo3{

	
	public static void main(String[] args) throws Exception {
		//获取Person类的类对象
		Person person = new Person("张三", "男",18);
		Class<? extends Person> cls= person.getClass();
		System.out.println(person);
		
		//getMethods():获取所有公共方法的对象,包括继承的父类的方法,数组
		Method[] methods = cls.getMethods();	
		System.out.println("输出公共方法名称,包括继承父类(Object)的方法:");
		for (Method method : methods) {
			System.out.print(method.getName()+"  ");
		}
		System.out.println("\n");
		//getMethod(name,Class<?>... parameterTypes)通过方法名获取类中方法的对象,仅限公共方法
		// name:方法名称	parameterTypes:形参列表对象的数据类型,若方法没有形参列表则可省略
		System.out.println("通过方法名获取类中方法的对象,仅限公共方法:");
		Method method = cls.getMethod("toString");
		System.out.println(method.getName()+"\n");
		
		//getDeclaredMethods():获取所有方法,包含私有方法,不包含继承的方法
		Method[] allDecMeth = cls.getDeclaredMethods();
		System.out.println("获取所有方法,包含私有方法,不包含继承方法:");
		for (Method meth : allDecMeth) {
			System.out.print(meth.getName()+"   ");
		}
		System.out.println("\n");
		//getDeclaredMethod(name,Class... types):获取指定的方法,可获取私有方法
		//		name:方法名	types:该方法的形参列表对应的类对象
		System.out.println("获取得到Person类中的私有方法pfun()");
		Method pMethod = cls.getDeclaredMethod("pfun", String.class);
		//方法对象.setAccessible(true):设置属性略过访问权限修饰符限制
		pMethod.setAccessible(true);
		//方法对象.invoke(对象名,实参列表):调用方法
		pMethod.invoke(person, "吃饭");

	}

}


输出:
Person [name=张三, sex=, age=18]
输出公共方法名称,包括继承父类(Object)的方法:
toString  getAge  setAge  wait  wait  wait  equals  hashCode  getClass  notify  notifyAll  

通过方法名获取类中方法的对象,仅限公共方法:
toString

获取所有方法,包含私有方法,不包含继承方法:
toString   pfun   getAge   setAge   

获取得到Person类中的私有方法pfun()
这是一个私有方法,你可通过该方法进行吃饭
类对象构造函数相关
getConstructors():获取公共的构造函数对象
getDeclaredConstructors():获取所有的构造函数
getDeclaredConstructor(types):获取指定的构造函数
	types:该构造函数的形参列表对应的类对象
	Constructor:构造函数对应的类
	构造函数对象.setAccessible(true):设置属性略过访问权限修饰符限制
	构造函数对象.newInstance(实参列表):创建该类的对象
        
举例:
类
public class Person {
	public String name;
	public String sex;
	private int age;
	public Person() {
		super();
	}
	
	private Person(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
	
}  

方法实现:
public class Demo4{
	public static void main(String[] args) throws Exception {
		//获取Person类的类对象
		Class<? extends Person> cls= Person.class;
		
		//getConstructors():获取公共的构造函数对象,包含包名
		System.out.println("获取类对象所拥有的所有公共构造函数的对象:");
		Constructor<?>[] constructors = cls.getConstructors();
		for (Constructor<?> constructor : constructors) {
			System.out.println(constructor.getName());
		}
		//getDeclaredConstructors():获取所有的构造函数,包括私有构造函数
		System.out.println("获取所有的构造函数,包括私有构造函数:");
		Constructor<?>[] decCons = cls.getDeclaredConstructors();
		for (Constructor<?> constructor : decCons) {
			System.out.println(constructor.getName());
		}
		//getDeclaredConstructor(types):获取指定的构造函数
		//	types:该构造函数的形参列表对应的类对象
		System.out.println("通过形参列表获取指定的构造函数\n之后通过获取到的构造函数创建对象:");
		Constructor<? extends Person> decCon = 
				cls.getDeclaredConstructor(String.class,String.class,int.class);
		//Constructor:构造函数对应的类
		//	构造函数对象.setAccessible(true):设置属性略过访问权限修饰符限制
		decCon.setAccessible(true);
		//构造函数对象.newInstance(实参列表):创建该类的对象
		Person person = decCon.newInstance("张三","男",36);
		System.out.println(person);
		
	}

}


输出:
获取类对象所拥有的所有公共构造函数的对象:
com.fs.demo01.Person
获取所有的构造函数,包括私有构造函数:
com.fs.demo01.Person
com.fs.demo01.Person
通过形参列表获取指定的构造函数
之后通过获取到的构造函数创建对象:
Person [name=张三, sex=, age=36]

枚举

定义
	访问权限修饰符 enum 枚举名{
		名1,名2,名3,...
	}
	注意:枚举中可以定义属性,方法,构造函数,但是没有意义;枚举是一个特殊的类,枚举中必要有枚举属性,所有构造函数都是私有的,枚举属性后的分号可写,可不写;如果在枚举属性下定义由普通方法、属性和构造函数的话必须写分号,但是可不写枚举变量直接写;表示枚举变量书写结束
使用
	一般情况:枚举名.名x
	switch中:名x
	
枚举与常量接口比较
	枚举可以限制传入的参数的取值范围(当形参为枚举类型时,传入的参数只能为枚举类中的值,而不能是其他值)

设计模式

因为在开发中大量使用,导致程序员对特殊情况的一些处理的方案进行总结
以便于下次遇到该情况可以快速解决的思路

单例

问题:一个类只能产生一个对象
思想:
	懒汉式
		1,私有化构造函数,此处可以保证无法直接通过new关键字创建该类对象
		2,在属性区声明一个该类的对象,使用private修饰
		3,提供一个公共的静态方法,在方法中返回唯一的一个该类对象
			判断步骤2中声明的对象是否为null
			如果为null创建一个对象,赋值给步骤2声明的对象
			直接返回步骤2的对象
		优点:在不使用的情况下,占据的内存较小
		缺点:目前的懒汉式是线程不安全的
		举例:
            //一个懒汉式单例
            public class LazyMan {
                private static LazyMan lazy=null;
                private LazyMan() {

                }

                public static LazyMan getLazy() {
                    if(lazy==null) {
                        lazy=new LazyMan();
                    }
                    return lazy;
                }
            }    
            
	饿汉式
		1,私有化构造函数,此处可以保证无法直接通过new关键字创建该类对象
		2,在属性区声明并创建一个该类的对象,使用private static修饰
		3,提供一个公共的静态方法,在方法中返回唯一的一个该类对象
			返回步骤2的对象
		优点:线程安全
		缺点:在不使用的情况下,占据的内存较大
        举例:
            //一个饿汉式单例
            public class HungryMan {
                private static HungryMan hm=new HungryMan();

                private HungryMan() {

                }

                public static HungryMan getHm() {
                    return hm;
                }
            }

	
	线程安全懒汉式
		就是给懒汉式创建对象的公共静态方法使用synchronized修饰
		优点:线程安全,在不使用的情况下,占据的内存较小
        举例:
            //一个线程安全的懒汉式单例
            public class LazyMan {
                private static LazyMan lazy=null;
                private LazyMan() {

                }

                public synchronized static LazyMan getLazy() {
                    if(lazy==null) {
                        lazy=new LazyMan();
                    }
                    return lazy;
                }
			}
		
	内部类形式的饿汉式
		1,私有化构造函数,此处可以保证无法直接通过new关键字创建该类对象
		2,在该类中提供一个静态内部类,在该类属性区声明并创建一个外部类对象
		3,提供一个公共的静态方法,该方法中返回步骤2中创建的对象
		优点:线程安全,在不使用的情况下,占据的内存较小
        举例:
            //内部类形式的饿汉式
            public class HungryMan {
                private HungryMan() {

                }
                static class Gethm{
                    private static HungryMan hm=new HungryMan(); 
                }
                public  static HungryMan getHm() {
                    return Gethm.hm;
                }
            }

工厂

一个方法可以生成多个数据类型不同的产品
举例:
父类:
	public abstract class Dog {
        private String type;

        public Dog() {
            super();
        }	
        public Dog(String type) {
            super();
            this.type = type;
        }
        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
        @Override
        public String toString() {
            return "Dog [type=" + type + "]";
        }
    }
子类:
    public class JinMao extends Dog{
        public JinMao() {
            super("金毛");
        }
    }
	
	
	public class TaiDi extends Dog{
        public TaiDi() {
            super("泰迪");
        }
    }
	
工厂类:
	public class Factory {

        public Dog getDog(Class c) {
            Dog dog = null;
            try {
                Constructor constructor = c.getDeclaredConstructor();
                constructor.setAccessible(true);
                dog = (Dog) constructor.newInstance();
            } catch (NoSuchMethodException | SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {
                return dog;
            }
        }
    }

测试类:
    public class Test {
        public static void main(String[] args) {
            Factory factory = new Factory();
            Dog dog = factory.getDog(JinMao.class);
            System.out.println(dog);
            Dog dog02 = factory.getDog(TaiDi.class);
            System.out.println(dog02);
        }
    }

	通过向工厂传入类对象,工厂通过类对象获取具体类中的构造函数来创建父类对象,然后将父类对象进行返回


总结:
	1,提供一个所有产品的父类或父接口
	2,让所有产品类可以继承或实现步骤1中的类或接口
	3,提供工厂类
	4,在工厂类中提供一个公共的方法,该方法的返回值就是步骤1的类或接口对象
		方式1:枚举或常量接口(通过switch进行选择)
			判断该方法传入的参数与枚举或常量接口中的那个值相同
			创建对应的对象,并返回
		方式2:使用反射机制
			使步骤4的形参为需要创建的产品的类的类对象
			使用类对象获取该类的构造函数对象
			使用构造函数对象创建该类对象对应的类的对象

注解

概念

注解:
	解释代码的代码就是注解(元代码)
元注解:
	解释注解的注解

常用注解

@Override
	表示对父类方法进行了重写
@Deprecated
	表示该方法、该类、该属性已经过时了,有更新更好的替代了
@SuppressWarnings
	忽略类、字段、方法、参数、构造方法的警告
	使用:	
		// 忽略全部类型的警告
        @SuppressWarnings("all")
        	
        // 忽略未检查的转化,例如集合没有指定类型的警告
        @SuppressWarnings("unchecked") 

        // 忽略未使用的变量的警告
		@SuppressWarnings("unused") 

		// 忽略与使用Closeable类型资源相关的警告
		@SuppressWarnings("resource")  

		// 忽略在类路径,原文件路径中有不存在的路径的警告
		@SuppressWarnings("path")   

        // 忽略使用了某些不赞成使用的类和方法的警告
		@SuppressWarnings("deprecation") 

        // 忽略switch语句执行到底没有break关键字的警告
		@SuppressWarnings("fallthrough") 

        // 忽略某类实现Serializable,但是没有定义serialVersionUID的警告
		@SuppressWarnings("serial") 
		
        // 忽略没有传递带有泛型的参数的警告
		@SuppressWarnings("rawtypes") 
        
        //同时忽略多种警告
        @SuppressWarnings({"警告类型1""警告类型2".....})

自定义注解

访问权限修饰符 @interface 注解名{
	public 数据类型 属性名();
	public 数据类型 属性名() default 默认值;
}
注意:
	如果定义的注解中的属性没有默认值,使用该注解时,必须传入值
	如果定义的注解中属性有默认值,在使用该注解时,可以选择是否需要传入
	注解的属性默认使用public修饰,也只能public修饰

注解的使用

可以在类,接口,方法,属性,局部变量,构造函数...上使用

语法规则:
	@注解名
	注意:只能使用没有属性的注解或注解中所有属性均有默认值
	
	@注解名(属性名1 = 值1,属性名2=值2)
	注意:此处属性名顺序可以与定义注解时属性不一致
	
	@注解名(值)
	注意:只有注解中的属性名为value时可以省略属性名不写
	
	注意:如果注解中的属性有默认值,可以在使用注解时不用给其中传入参数

元注解

概念:解释注解的注解

常用元注解:
	@Documented:生成文档
	@Retention:注解起作用的时机
		1,代码编写:RetentionPolicy.SOURCE
		2,代码编译与代码编写:RetentionPolicy.CLASS
		3,代码运行,代码编译,代码编写RetentionPolicy.RUNTIME
	@Target:限定注解的使用位置
		ElementType.TYPE:可以在类,接口,枚举上用
		ElementType.FIELD:可以在属性上使用
		ElementType.METHOD:可以在方法上使用
		ElementType.PARAMETER:可以在形参前使用
		ElementType.CONSTRUCTOR:可以在构造函数上使用
		ElementType.LOCAL_VARIABLE:可以在局部变量上使用
		ElementType.ANNOTATION_TYPE:可以在注解上使用
		ElementType.PACKAGE:可以在包上使用
		注意:如果注解上没有该注解,说明该注解可以在任何地方使用,因为默认值all
	@Inherited:注解是否可以被继承
		默认是不能被继承的,加上该注解就可以被继承了

注解与反射的结合

获取的注解被元注解@Retention(RetentionPolicy.RUNTIME)进行修饰,否则获取得到的注解对象为空。

注解类型 注解对象 = 类对象.getAnnotation(注解的类对象):获得指定的注解对象
使用注解对象.属性名():获取注解中的属性值
    
    
举例:
注解:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	public int test();
	public String error() default "ERROR";
}

测试类:
@MyAnnotation(test=404)
public class Test {
	public static void main(String[] args) {	
		Class<Test> te=Test.class;
		MyAnnotation annotation =te.getAnnotation(MyAnnotation.class);
		System.out.println(annotation);
	}
}

输出结果:
@com.fs.intface.MyAnnotation(error=ERROR, test=404)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值