Java笔记23反射,设计模式

本文主要介绍Java的反射和设计模式。反射自JDK1.5引入,提高了代码灵活性,可用于操作第三方类库。文中介绍了类对象概念、获取方式及常用方法,还阐述了设计模式规则,包括单例、工厂、消费者等模式,最后提及枚举的作用、定义和使用。

反射

        JDK1.5引入

        优点:提高了代码的灵活性,使java语言从静态语言变为半动态语言

        创建对象:

                        先创建类,在类中定义属性,定义方法,使用new关键字创建该类对象

        反射使用场景:

                        1,使用第三方类库时,可以创建其对象,但是不知道对象拥有的属性与方法,此时

                            就以通过反射进行获取

                        2,使用三方类库,只知道类名,但是不知道类中有什么,可以使用反射进行获取与使用                         3,使用三方类库,只知道类所在的包名与类名,但是操作.可以使用反射对其进行操作

类对象

概念

        一个类被JVM加载时,会生成一个类对象 类对象中包含了该类的属性,方法,构造函数,父类,父接口等信息

        注意: 一个类只会被JVM加载一次,所以一个类的类对象只有一个

         通过new关键字创建出来的对象,称为类的对象,又名实例对象.与类对象不是一个东西

获取类对象的方式

        方式1:

                通过实例对象,getClass()方法获取

                

	Student stu = new Student();//
		
		Class class1 = stu.getClass();//通过实例对象获取

        方式2:

                通过类名获取类的对象

                类名.class

Class class2 = Student.class;//使用类名获取

        方式3:

                通过Class类提供的静态方法获取

                Class.forName("包名,类名");

        

Class class3 = Class.forName("dome01.Student");//使用类名与包名获取

        

        System.out.println(class1);//打印下
		System.out.println(class2);
		System.out.println(class3);

类对象的常用方法

概述:获取该类的信息

   1.     获取类的全名称(包名+类名) String getName()

        获取类名 String getSimpleName();

        System.out.println(class1.getName());//获取类全名
		System.out.println(class1.getSimpleName());//获取类名

        获取类加载器 ClassLoader getClassLoader();

ClassLoader loader = class1.getClassLoader();//获取类加载器

        类加载器负责在运行时将 Java 类动态加载到 JVM (Java 虚拟机)。它们也是 JRE(Java 运行时环境)的一部分。因此,借助类加载器,JVM 无需了解底层文件或文件系统即可运行 Java 程序。

        此外,这些 Java 类不会一次全部加载到内存中,而是在应用程序需要它们时才会进行加载。这就是类加载器发挥作用的地方,他们负责将类加载到内存中。

    

2. 获取父类 Class getSuperclass();

	Class superclass = class1.getSuperclass();//获取父类

         获取父接口 Class[] getInterfaces();

        Class[] interfaces = class1.getInterfaces();//获取父类接口
		for (Class classtese : interfaces) {
			
		}
由于接口可能有多个,所有需要数组存储

     3.   获取包 Package getPackage();

                方法: getName()获取包名

        Package package1 = class1.getPackage();//获取包
		package1.getName();//获取包名

     4.    通过类对象创建类的实例对象

                Object newInstance();

                 注意1:如果该类中没有无参构造函数,那么此时方法将出现NoSuchMethodException异常                  注意2:如果该类的无参构造访问权限不足,此时方法将出现IllegalAccessException异常         获取属性

        Object newInstance = class1.newInstance();//通过类对象创建实例
		Student student2 = (Student)newInstance;//需要强转 

      5.

         获取类的所有公共属性

                 注意:可以获取到父类的公共属性

                         Field[] getFields();

Field[] fields = class1.getFields();//获取父类的公共属性

      

          获取本类的所有属性(包括私有属性)

                 注意:只能获取本类的所有属性

                         Field[] getDeclaredFields();

Field[] declaredFields = class1.getDeclaredFields();//获取本类属性

        获取指定的属性

                Field getDeclaredField("属性名");

               

Field declaredField = class1.getDeclaredField("age");//获取指定属性
	

         

6.获取构造函数

        获取类的所有公共构造函数

         Constructor[] getConstructors();

Constructor[] constructors = class1.getConstructors();//获取所有公共构造函数

        获取类的所有构造函数

         Constructor getDeclaredConstructors();

Constructor[] declaredConstructors = class1.getDeclaredConstructors();//获取该类所有的构造函数

        获取类的指定构造函数

         Constructor getDeclaredConstructor(获取构造函数的参数列表的类对象列表);

Constructor<? extends Student> declared2 = class1.getDeclaredConstructor(String.class, int.class);//获得有参构造,根据传入参数的个数,获取到的构造函数也不同

Student student3 = declared2.newInstance("3",12);//使用构造函数创建对象




Constructor<? extends Student> declared3 = class1.getDeclaredConstructor( int.class);
	
		declared3.setAccessible(true);
		
		Student student3 = declared3.newInstance(6);

当构造函数被私有修饰时,可以用setAccessible(true);方法绕过后创建

7.获取方法

        获取类中所有公共方法

                 Method[] getMethods();

                注意:可以获取到父类提供的公共方法(不包含私有)

	Method[] methods = class1.getMethods();//获取所有的公共类方法,可以获取到父类的公共方法

         获取类中所有方法

                 Method[] getDeclaredMethods();

                注意:只能获取该类的所有方法

       

Method[] methods = class1.getMethods();//获取所有的公共类方法,可以获取到父类的公共方法
	
		Method[] methods2 = class1.getDeclaredMethods();
		for (Method method : methods2) {
			
			System.out.println(method);
			
		}

没有构造方法

 

获取类中指定方法

                 Method invoke(String name, Class... p)

                参数1:方法名

                参数2:该方法形参列表对应的类对象列表

           如:获取下eat方法,setAge方法

	mo1.invoke(student);//执行方法,参数为对象名,方法的参数
		mo2.invoke(method2, 23);//
		
m01.setAccessible(true);
同样的,可以绕过权限修饰符

Field类

        常用方法:

                修改对象的属性值

                         void set(对象, 修改后的值)

                        

                 获取对象的属性值

                         Object get(对象);

                 略过访问权限修饰符

                        void setAccessible(true);

                获取属性名

                         String getName();

Constructor类

                常用方法:

                         创建对象 

        T newInstance(实参列表)


Constructor<? extends Student> declared3 = class1.getDeclaredConstructor( int.class);
	
		declared3.setAccessible(true);
		
		Student student3 = declared3.newInstance(6);

                               

                        略过访问权限修饰符

                                 void setAccessible(true);

Method类

                常用方法:

                        作用:执行方法

                        Object invoke(Object obj, Object... args)

                         参数:

                                 obj:执行该方法的对象

                                 args:实参列表

                        返回值:

                                执行的方法的返回值

	mo1.invoke(student);//执行方法,参数为对象名,方法的参数
		mo2.invoke(method2, 23);//
		

                        略过访问权限修饰符

                        void setAccessible(true);

m01.setAccessible(true);
同样的,可以绕过权限修饰符

                       

设计模式

        一套被反复使用,多数人知道,经过分类,代码设计经验的总结 简单的理解为:设计模式就是解决固定问题的方案

设计模式规则

        单一职责:一个方法或接口或类..只干一件事

        开闭原则:对扩展开放,对修改关闭

        里式替换:子类可以扩展父类的功能,但不能改变父类原有的功能。

        依赖倒置:对抽象进行编程,不要对实现进行编程,这样就降低了程序与实现模块间的耦合

        接口隔离:使用多个专门的接口比使用单个接口要好很多。

        迪米特法则:一个类对于其他类知道的越少越好

单例模式

解决问题:一个只产生一个对象的类

分类:

                饿汉式

                         步骤: 1,私有构造函数,此时外部就无法通过new调用构造函数创建对象

                                  2,在该类中提供一个私有的静态的不可修改的该类对象

                                 3,提供公共静态方法,该方法返回步骤2的对象

                                        以后需要外部需要该类对象只能使用类名.步骤3提供的静态方法得到

                                                         优点:线程安全

                                                         缺点:浪费内存,在类加载时就会创建对象

public class YuanBao {
	private static final YuanBao yb=new YuanBao();

	private void YuanBao(){
		
	}
	
	public static YuanBao getInstance() {
		return yb;
	}
}

                                     

                懒汉式 线程不安全

                                步骤: 1,私有构造函数 

                                          2,在该类中声明一个静态该类对象

                                         3,提供公共静态方法,方法中 判断步骤2的对象是否为空

                                          .如果为空创建对象,赋值给该属性.在返回该类对象.如果

                                           不为空直接返回

                                                优点:不浪费内存

                                                缺点:只能应用与单线程情况下

public class YuanBao {
	private static  YuanBao yb;

	private void YuanBao(){
		
	}
	
	public static YuanBao getInstance() {
		if(yb==null) {
			yb=new YuanBao();
		}

		return yb;
	}
}

                        优化:可在基础上加上锁,但是会影响效率,多个线程使用会降低速度

                          优化:静态内部类实现懒汉式       

public class YuanBao {
	

	private void YuanBao(){
		
	}
	
	public static YuanBao getInstance() {
		return Yuzhe.YUAN_BAO;
	}
	
	private static class Yuzhe{
		
		public static final YuanBao YUAN_BAO = new YuanBao();
		//内部类不加载就不会创建,私有的也不会导包
	}
	
}

工厂模式

解决问题:对于类似的事物, 一个方法只能使用一种对象,

如:不同的动物,狗和猫需要使用同一种方法,如果一种动物使用一种方法,就会显得繁琐。

package work3;

abstract class Animal {
	String name;	
	public Animal() {
		super();
		
	}
	public Animal(String name) {
		super();
		this.name = name;
	}
	void enjoy() {};	
}
package work3;

public class Cat extends Animal{
	private String eyesColor;
	public Cat() {
		super();
	
	}
	public Cat(String name,String eyesColor) {
		super(name);
		this.eyesColor=eyesColor;		
	}
	public String getEyesColor() {
		return eyesColor;
	}
	public void setEyesColor(String eyesColor) {
		this.eyesColor = eyesColor;
	}
	public void enjoy() {
		System.out.println( name+"猫开心笑");
	}

}

package work3;

public class Dog extends Animal{
	private String furColor;
	
	public Dog() {
		super();
	}

	public Dog(String name,String fuString) {
		super(name);
		
	}
	public String getFurColor() {
		return furColor;
	}

	public void setFurColor(String furColor) {
		this.furColor = furColor;
	}

	public void enjoy() {
		System.out.println( name+"狗开心叫");
	}

}

package work3;

public class Lady {
	private String name;
	private Animal pet;
	public Lady() {
		super();
	}
	public Lady(String name, Animal pet) {
		super();
		this.name = name;
		this.pet = pet;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Animal getPet() {
		return pet;
	}
	public void setPet(Animal pet) {
		this.pet = pet;
	}
	public void myPetEnjoy(Animal pet) {
		
		System.out.println(name+"逗"+pet.name);
		if(pet instanceof Dog) {
			Dog dog=(Dog)pet;//在方法这需要判断
			dog.enjoy();
			
		}
		if(pet instanceof Cat) {
			
			Cat cat=(Cat)pet;
			cat.enjoy();
		}
		
	}

}

package work3;

public class Test {
	public static void main(String[] args) {
		
		Cat cat = new Cat("汤姆","蓝");
		Dog dog = new Dog("斯派克","灰");
		Lady lady = new Lady("张女士",cat);
		Lady lady2 = new Lady("张女士",dog);
		
		lady.myPetEnjoy(cat);
		System.out.println();
		lady2.myPetEnjoy(dog);
		
	}
}

消费者模式

线程那块写了

监听者模式(等待补充)

枚举

作用:限定值的取值范围

注意:

        枚举是一种引用数据类型

         枚举变量的值必须是枚举常量

        枚举中可以定义普通的属性,方法与私有的构造函数

        如果枚举中只有枚举常量,此时可以忽略分号不写.多个枚举常量直接使用逗号隔开

        如果枚举中定义了普通属性等,此时枚举常量最后需要使用分号

        

         枚举的定义:

                 访问权限修饰符 enum 枚举名{

                        枚举常量名1,枚举常量名2,...

         }

枚举的使用:

                声明变量

                作为形参

public enum Myenum {
	ZHUOZI,YIZI,YIGUI;//里面也不会创建对象
	private String nameS;
	public void test() {
		
	}
	private Myenum() {
		
	}
}
package dome02;

public class JJGongChang {
	public static JiaJu getBean(Myenum myMenu) {
		if (myMenu == Myenum.ZHUOZI) {
			return new ZhuoZi();
		}else if(myMenu == Myenum.YIGUI) {
			return new YiZi();
		}
		return null;
	}

}

abstract class JiaJu{
	
}

class ZhuoZi extends JiaJu{
	
}
class YiZi extends JiaJu{
	
}

这样传参就只能使用枚举里面的名称

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值