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:编译时直接丢弃这种策略的注释