Java基础day19----反射

1.什么是类对象

类的对象与类对象区别:
1.类的对象:基于某个类new出来的对象,也称实例对象。
2.类对象:类加载的产物,封装了一个类的所有信息

获取类对象:
1、通过类的对象,获取类对象

Person p=new Person();
Class c=p.getClass()

2、通过类名获取类对象

语法:Class c=类名.class
Class c=Person.class;

3、通过 静态方法获取类对象

语法:Class c=Class.forName("包名.类名");
Class c=Class.forName("com.hp.demo.Person");

注:推荐使用第三种,前两种依赖性强。

2.反射常用的方法
1、public String getName() //获取类的全名称
2、public Package getPackage()
3、public Class<? super T> getSuperclass()
4、public Class<?>[] getInterface()

//获取类对象
		Class class1=Class.forName("com.hp.demo.Person");
		
		//1.获取类的全名称getName()
		String name=class1.getName();
		System.out.println(name);//com.hp.demo.Person
		
		//2.获取包名getPackage()
		Package packageName = class1.getPackage();
		System.out.println(packageName);//package com.hp.demo
		System.out.println(packageName.getName());//com.hp.demo
		
		//3.获取父类 getSuperClass()
		System.out.println(class1.getSuperclass());//class java.lang.Object
		System.out.println(class1.getSuperclass().getName());//java.lang.Object
		
		
		//4.获取接口getInterfaces()
		Class[] cs=class1.getInterfaces();
		for (Class cl : cs) {
			System.out.println(cl);
		}

5、public Constructor<?>[] getConstructors()
6、public T newInstance()

// 获取类对象
		Class<?> class1 = Class.forName("com.hp.demo.Person");

		// 1.使用反射获取类的构造方法
		Constructor[] cons = class1.getConstructors();
		for (Constructor constructor : cons) {
			System.out.println(constructor);
			/**
			 * 打印结果: public com.hp.demo.Person() public
			 * com.hp.demo.Person(java.lang.String,int)
			 */
		}

		// 2.实例化newInstance()
		//2.1简便方法
		 Object newInstance = class1.newInstance(); //这个必须要有无参构造方法
		 System.out.println(newInstance);//无参构造执行了。。。 Person [name=null, age=0]
		//2.2先得到无参构造方法,再调用实例方法 
		Constructor<?> constructor = class1.getConstructor();
		Object newInstance1 = constructor.newInstance();
		System.out.println(newInstance1);//无参构造执行了。。。 Person [name=null, age=0]
		//2.3先得到有参构造方法,再调用实例方法
		Constructor<?> constructor2 = class1.getConstructor(String.class,int.class);
		Person xiaoli=(Person)constructor2.newInstance("小丽",20);
		System.out.println(xiaoli);//Person [name=小丽, age=20]

7、public Method[] getMethods()

 //1.1获取方法 Method[] methods=class1.getMethods();//获取公开的方法,包括从父类继承的方法 
 			for(Method method : methods) 
 			{ System.out.println(method); }
		  System.out.println("----------------"); 
//1.2获取方法 Method[]
		  methods1=class1.getDeclaredMethods();//获取类中的所有方法(包括私有、默认、保护的,但是不包括继承的)
		 for(Method method:methods1)
		  { System.out.println(method); }
		  System.out.println("----------------"); 
//1.3获取单个方法 Method
		 studyMethod=class1.getMethod("study"); System.out.println(studyMethod);
	//2.利用反射调用方法 
	Person person=(Person) class1.newInstance();
		 studyMethod.invoke(person);//相当于之前的person.study();

8、public Field[] getFields()

// 获取类对象
		Class<?> class1 = Class.forName("com.hp.demo.Person");
		
		//1.1获取字段
		Field[] fields=class1.getFields();//获取公开的字段、父类继承的字段
		System.out.println(fields.length);//0
		//1.2获取字段getDeclaredFields()
		Field[] fields1=class1.getDeclaredFields();//获取所有的属性,包括私有的,但是不包括继承的
		System.out.println(fields1.length);
		for(Field field:fields1) {
			System.out.println(field);
		}
		/**
		 * 打印结果:
		 * 2
		 * private java.lang.String com.hp.demo.Person.name
		 * private int com.hp.demo.Person.age
		 */
		//1.3获取单个字段
		Field ageField=class1.getDeclaredField("age");
		System.out.println(ageField);
		Person zhangsan =(Person)class1.newInstance();
		ageField.setAccessible(true);//设置私有属性无效(方法亦是如此)
		ageField.set(zhangsan, 30);//zhangsan.age=30;
		
		System.out.println(ageField.get(zhangsan));

3.设计模式

什么是设计模式?
一套被反复使用、多数人知晓的、经过分类编目的。代码设计经验的总结。简单理解:特定问题的固定解决方法。
好处:使用设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码的可靠性、重用性。


1工厂设计模式
工厂设计模式有一个非常重要的原则"开闭原则",对拓展开放,对修改关闭。
可通过反射进行工厂模式的设计,完成动态的对象创建。

步骤一:首先创建一个Usb接口,给一个抽象方法service()
步骤二:然后创建鼠标、键盘、u盘类去实现Usb接口,并实现service()方法
步骤三:创建一个工厂类去生产这些鼠标、键盘等(在src下有一个属性文件db.properties)
在这里插入图片描述

package com.hp.demo1;

public class UsbFactory {
	
	public static void createUsb(String type) throws Exception {//type获取类的全名称
		
	Class class1=Class.forName(type);
	Usb usb=(Usb)class1.newInstance();
	usb.service();
	
		
	}

}

在测试类中:

	Scanner sc=new Scanner(System.in);
		
		Properties properties=new Properties();
		FileInputStream fis=new FileInputStream("src\\db.properties");
		properties.load(fis);
		
		while(true) {
			System.out.println("请选择1鼠标 2风扇  3u盘");
			String input=sc.next();
			
			
			UsbFactory uf=new UsbFactory();
			uf.createUsb(properties.getProperty(input));

此时如果需要添加其他产品,则只需要它实现Usb接口,然后再在db.properties内添加即可。。。
注:很重要,需要多看几遍


2单例模式
单例:只允许创建一个该类的对象
方式1:饿汉式(类加载时创建,天生线程安全)

步骤一:首先创建一个常量
步骤二:把构造方法私有化
步骤三:通过一个公共的方法来返回这个对象

 `class Singleton{
> private static final Singleton instance=new Singleton();
> private Singleton(){}//把构造方法私有化
> public static Singleton getInstance(){  //提供一个公共的方法去实例化
> return instance;
> }
> 
> }`

测试以下是否线程安全

	for(int i=0;i<3;i++) {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					System.out.println(Singleton.getInstance());//打印的结果都是同一个地址
					
				}
			}).start();
		}

方式2:懒汉式(使用时创建,线程不安全,加同步)

 `class  Singleton2{
 private static  Singleton instance=null;
 private Singleton2(){}
 if(instance==null){
 instance=new Singleton2();
 }
 return instance;
 }`

测试类:

for(int i=0;i<3;i++) {
	new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println(Singleton2.getInstance());//打印的同一地址
				
			}
		}).start();

饿汉式单例和懒汉式单例的优缺点:
饿汉式的优点:线程安全,缺点:即使不使用这个单例对象,也会占用空间,生命周期长
懒汉式的优点:生命周期短,节省空间,缺点:线程不安全

有个结合懒汉式和饿汉式的方法,但是这里就不再写了,先把这个整明白就可以了。


4.枚举类型

枚举是一个引用类型,枚举规定了取值范围的数据类型。
枚举常量不能使用其他数据,只能使用枚举中的常量赋值,提高程序的安全性。(暂时理解不了)
定义枚举需要使用enum :public enum 类名
(1)枚举中必须包含枚举常量,也可以包含属性、方法、私有构造方法
(2)枚举常量必须写在前面,多个常量之间使用逗号隔开,最后分号可写可不写

public enum Gender {
	MALE,FEMALE;//常量必须放在前面(最好大写。。),而且必须包含常量,否则代码报错
}

测试类:

	Gender gender=Gender.FEMALE;//不能用new,因为其构造方法是私有的

枚举的本质是一个终止类,并继承Enum抽象类。
枚举中的常量就是当前类型的常量。

5注解

1、什么是注解?
注解(Annotation)是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件。
2、开发人员可以通过注解告诉类如何运行
在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类
3、常见的注解:@override @Deprecated
4、定义注解使用@interface关键字,注解只能包含属性

注解的属性类型:
String 类型、基本数据类型、Class类型、枚举类型、注解类型,以上类型的一维数组

步骤一:创建一个注解

package com.hp.demo4;

public @interface MyAnnotation {
	//定义属性
	String name() default "张三";
	int age() default 20;
	

}

步骤二:在某一个类中添加注解

package com.hp.demo4;

public class PersonInfo {
	
	@MyAnnotation(name="李四",age=30)
	public void show(String name,int age) {
//		System.out.println("name="+name+",age="+age);
		
	}

}

步骤三:获取注解信息

package com.hp.demo4;

import java.lang.reflect.Method;

public class Demo {

	public static void main(String[] args) throws Exception {
		
		//获取类对象
		Class<?> class1 = Class.forName("com.hp.demo4.PersonInfo");
		//获取方法
		Method method=class1.getMethod("show", String.class,int.class);
		
		//通过方法获取注解
		MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
		
		System.out.println(annotation.age());
		System.out.println(annotation.name());
	}

}

结果:
java.lang.NullPointerException
解决方案:在注解类上面添加
在这里插入图片描述
结果就变成了:李四 30

元注解:用来描述注解的注解
@Retention:用于指定注解可以保留的域
(1)RetentionPolicy.CLASS:注解记录在class文件中,运行Java程序时,JVM不会保留,这是默认值
(2)RetentionPolicy.RUNTIME:注解记录在class文件中,运行Java程序时,JVM会保留注解,程序可以通过反射获取该注释
(3)RetentionPolicy.SOURCE:编译时直接丢弃这种策略的注释

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值