目录
一、反射概述
概述:反射其实就是类对象,类加载的产物;将类加载到内存中,会产生类对象(class文件);有了类对象,即可得到所有类资源的信息: 类,方法,属性,构造器,包,父类,接口...
即通过反射得到类对象,通过类对象可以得到类的实例对象,属性对象,方法对象,在反射中 对类的资源的操作都通过资源的对象进行操作
为什么要用反射?
通过反射,可以在编译时不需要知道类的名字,从而在程序运行时根据需要动态的确定要使用的类,并且动态创建类的实例对象、操作属性对象(甚至是私有的)、方法对象,使得程序更加的灵活、维护性更强
1.创建类对象
创建类对象可以通过三种方式:
1. 类名.class
2. 对象.getClass()
3.Class.forName("全限定名")
无论哪种方式获取的类对象都是同一个类对象(因为类对象其实就是class对象,类在编译时只会生成一份解释文件 .class文件,所以通过这三种方法得到的都是同一个class对象(类对象))
演示:
//1.通过类名获取类对象
Class<?> c1 = Person.class; //<?>:通配所有类型,用在接收数据据时
Class c2 = new Person().getClass();
Class c3 = Class.forName("com.qf.f_reflect.Person");
System.out.println(c1==c2); //true
System.out.println(c1==c3); //true
2.常用方法:
//反射的相关方法
Class c1 = Student.class; //获取反射对象
System.out.println("获取类名:"+c1.getName());
System.out.println("获取包名:"+c1.getPackage());
System.out.println("获取父类:"+c1.getSuperclass());
System.out.println("获取接口:"+Arrays.toString(c1.getInterfaces()));
//getField或getFields获取公开的属性的
System.out.println("获取属性:"+Arrays.toString(c1.getFields()));
//System.out.println("获取指定属性:"+c1.getField("name"));
//获取非空开属性;甚至放开权限后,私有的也可以获取
System.out.println("获取属性2:"+Arrays.toString(c1.getDeclaredFields())); //常用
System.out.println("获取方法:"+Arrays.toString(c1.getMethods())); //常用
//参数1:方法名 参数2:多个参数
System.out.println("获取指定方法:"+c1.getMethod("hi",String.class,int.class));
System.out.println("获取构造器:"+Arrays.toString(c1.getConstructors()));
System.out.println("实例化对象:"+c1.newInstance()); //(常用)
二、反射应用
1.调属性
class Person{
private String name;
private int age;
}
public class Test1 {
public static void main(String[] args) throws Exception{
//通过反射对象调属性:
//1.获取类对象
Class c1 = Person.class;
//2.获取Field对象
Field field = c1.getDeclaredField("name");
//3.给定权限,即可调用私有属性
field.setAccessible(true);
//4.field调用set方法进行赋值
Object o = c1.newInstance();
field.set(o, "张三丰");
//验证数据是否存进去:get
System.out.println(field.get(o));
//System.out.println(((Person)o).name);
}
}
2.调方法
class Student {
public void hello(String name,int age) {
System.out.println("姓名:"+name+";年龄:"+age);
}
public void test() {
}
}
public class Test2 {
public static void main(String[] args) throws Exception {
//类对象调方法:
//1.获取类对象
Class c1 = Student.class;
//2.获取Method对象
Method method = c1.getMethod("hello", String.class,int.class);
//3.调用invoke方法
method.invoke(c1.newInstance(), "zs",33);
}
}
3.应用场景:
反射应用,往往可以灵活动态的调用属性,方法,构造方法
在程序中,使用了反射,可以使程序的维护性更强
field.set(t, name); 给实例对象t的属性filed 设置值为name
//反射应用场景:灵活获取对象及属性资源
//案例:灵活动态地获取对象,例如:调指定方法返回Dog对象,或返回Cat
class Cat{
String name;
@Override
public String toString() {
return "Cat [name=" + name + "]";
}
}
class Dog{
String name;
@Override
public String toString() {
return "Dog [name=" + name + "]";
}
}
class Factory{
public final static int F_DOG=1;
public final static int F_CAT=2;
public static Dog getDog() {
return new Dog();
}
public static Cat getCat() {
return new Cat();
}
public static Object getObject(int f) {
if(f==F_DOG) { //违背ocp原则:对内修改的代码要持关闭状态
return new Dog();
}else if(f==F_CAT) {
return new Cat();
}else {
return null;
}
}
//泛型方法定义:<T>
public static <T> T getObject(Class<T> c1,String name) throws Exception {
Field field = c1.getDeclaredField("name");
field.setAccessible(true);
T t = c1.newInstance();
field.set(t, name);
return t;
}
}
public class Test3 {
public static void main(String[] args) throws Exception {
//1.面向对象方式获取对象:
//问题:如果获取30个不同对象,则需要30个方法; 冗余代码太多
Dog dog = Factory.getDog();
Cat cat = Factory.getCat();
//2.传入标记获取对象(调一个方法)
//问题:违背ocp原则;耦合性太强; 维护性太差
Dog d = (Dog)Factory.getObject(Factory.F_DOG);
Cat c = (Cat)Factory.getObject(Factory.F_CAT);
//3.反射用法
Dog dd = Factory.getObject(Dog.class,"旺财");
Cat cc = Factory.getObject(Cat.class,"加菲猫");
System.out.println(dd+"---"+cc);
}
}
三、设计模式
概述:反复被使用的一套设计标准;也可以理解为特定问题的固定解决方案。
好处:可读性,复用性,维护性更强
分类:23种设计模式,总共分3类
对象型模式:针对对象的获取 例如:单例,工厂
结构型模式:针对对象的组织结构 例如:装饰者,代理
行为型模式:针对对象的行为跟踪 例如:观察者
四、工厂模式
概述:从工厂类中根据标记获取不同的对象
//动物的工厂类; 里面获取出不同的对象
class Factory{
public static final int F_DOG=1;
public static final int F_CAT=2;
public static Object getObject(int f) {
if(f==F_DOG) { //违背ocp原则
return new Dog();
}else if(f==F_CAT) {
return new Cat();
}else {
return null;
}
}
//泛型方法:
public static <T> T getObject(Class<T> c) throws Exception {
return c.newInstance();
}
}
class Dog{}
class Cat{}
public class Test1 {
public static void main(String[] args) throws Exception {
//1.基本工厂设计模式:
//a.静态工厂: 调静态方法(常用)
//b.实例工厂: 实例化工厂对象调成员方法
Dog dog = (Dog) Factory.getObject(Factory.F_DOG);
//2.工厂+反射+配置文件
//“约定大于配置(约定规则取代配置-框架常用);配置大于编码(硬编码->软编码)”
Properties p = new Properties();
p.load(new FileInputStream("factory.properties"));
String path = p.getProperty("1"); //key已知;value变为的
System.out.println(Factory.getObject(Class.forName(path)));
}
}
五、单例模式
概述:每次获取到的对象都是同一个对象
单例设计:
1.类名调用静态方法; 2.返回静态属性 3.构造方法私有化
好处:节省内存资源
1.单例分类
/单例设计的分类: 饿汉式,懒汉式
class MySingle{
//private static final MySingle single = new MySingle(); //饿汉式(常用)
private static MySingle single; //懒汉式:调用方法时才去new对象
private MySingle() {}
public static MySingle getInstance() {
if(single==null) {
single = new MySingle();
}
return single;
}
}
public class Test1 {
public static void main(String[] args) {
//单例:
MySingle my = MySingle.getInstance();
MySingle my2 = MySingle.getInstance();
System.out.println(my==my2); //true
}
}
2.懒汉隐患
如果多个线程去通过懒汉模式创建单例对象,那么多个线程可能执行到 判断对象为空,但是还没执行创建对象的操作,那么这个时候可能就存在多个线程创建对象,这样就不能确保每次获取的都是同一个对象
如何解决懒汉隐患:当对象为空的时候,加锁,然后继续判断对象是否为空,为空则创建对象
为什么外层还需要判断线程是否为空,因为不加判断,每个线程都会等待锁资源的释放,加了后只有在对象没有被创建、为空的时候,线程才会等待锁资源的释放,尝试去创建对象,当对象不为空直接将这个对象返回,通过外层的判断使得不需要所有的线程都需要等待,提高了性能
代码案例:
class MySin{
private static MySin sin;
private MySin() {}
public static MySin getInstance() {
//隐患问题:共享数据sin,有复合操作---安全隐患
if(sin==null) { //完整的线程安全处理--性能高
synchronized("lock") {
if(sin==null) {
System.out.println("------");
sin = new MySin();
}
}
}
return sin;
}
}
public class Test2 {
public static void main(String[] args) {
for(int i=1;i<=10;i++) {
new Thread(new Runnable() {
@Override
public void run() {
MySin.getInstance();
}
}).start();
}
}
}
六、枚举
概述:枚举和静态常量类似,都是作为状态值来使用;
当状态值设置的比较少,可以选择静态常量;状态值设置的较多,则选择枚举(写法上更;简洁)
枚举的定义: 创建枚举类后,里面可以生成很多枚举值;这些枚举值的维护性较好
案例:
//枚举的本质:继承Enum的最终类 枚举值则是封装后的静态常量
enum MyEnum{ //创建枚举类
M_DOG,M_CAT
}
class Factory{
//public static final int F_DOG=1; //静态常量
//public static final int F_CAT=2;
public static Object getObject(MyEnum f) {
if(f==MyEnum.M_DOG) { //违背ocp原则
return new Dog();
}else if(f==MyEnum.M_CAT) {
return new Cat();
}else {
return null;
}
}
}
class Dog{}
class Cat{}
public class Test1 {
public static void main(String[] args) throws Exception {
//1.基本工厂设计模式:
Dog dog = (Dog) Factory.getObject(MyEnum.M_DOG);
}
}
七、注解
概述:注解可以参与程序代码中的执行;往往在框架中可以取代相关配置信息
回顾使用过的注解:@Test(单元测试-功能型注解) @Override(重写注解-检测型注解)
@interface注解类: 定义当前类中只能使用属性
1.注解回顾
//回顾注解的用法:
class Animal{
public void bark() {}
}
@Deprecated //定义该类为过时的类
class Dog extends Animal{
@Deprecated //定义该方法是过时的方法
@Override //检测型注解-检测是否为重写方法
public void bark() {}
}
public class Test1 {
public static void main(String[] args) {
}
@Test //JVM会生成Test1类的对象调成员方法
public void show() {
System.out.println("xxxx");
}
}
2.注解类
enum MyEnum{
A,B
}
@interface MyAnno{}
//@interface注解类:定义当前类中只能使用属性
@interface MyAnnotation{
int age() default 66; //定义int类型属性
String name(); //定义String类型
Class c1(); //类对象类型
MyEnum enum1() default MyEnum.A; //枚举类型
MyAnno anno();
}
public class Test2 {
public static void main(String[] args) {
}
}