反射
简介
JDK1.5引入
优点:提高了代码的灵活性,使java语言从静态语言变为半动态语言
创建对象:
先创建类,在类中定义属性,定义方法,使用new关键字创建该类对象
反射使用场景:
1.使用第三方类库,可以创建其对象,但是不知道对象拥有的属性与方法,如果想获取,此时就可以通过反射进行获取
2.使用第三方类库,只知道类名,但是不知道类中有什么,可以使用反射进行获取与使用
3.使用第三方类库,只知道类所在的包名与类名,但是想操作,可以使用反射对其进行操作
类对象
概念
一个类被JVM加载时,会生成一个类对象
类对象中包含了该类的属性,方法,构造函数,父类,父接口等信息
注意:
一个类只会被JVM加载一次,所以一个类的类对象只有一个
通过new关键字创建出来的对象,称为类的对象,又名实例对象,与类对象不是一个东西
获取类对象的方式
方式1:
通过类的实例对象.getClass()获取类对象
方式2:
通过类名获取类对象
类名.class
方式3:
通过Class类提供的静态方法获取
Class.forName("包名.类名");
类对象的常用方法
概述: 获取该类信息
获取类的全名称(包名+类名)
String getName()
获取类名
String getSimpleName();
获取类加载器
ClassLoader getClassLoader();
获取父类
Class getSuperclass();
获取父接口
Class[] getInterfaces();
获取包
Package getPackage();
方法:
getName()获取包名
通过类对象创建类的实例对象
Object newInstance();
注意1: 如果该类中没有无参构造函数,那么此时方法将出现NoSuchMethodException异常
注意2: 如果该类的无参构造函数访问权限不足,此时方法将出现IllegalAccessException异常
获取属性
获取类的所有公共属性
注意:可以获取到父类的公共属性
Field[] getFields();
获取本类的所有属性
注意:只能获取本类的所有属性
Field[] getDeclaredFields();
获取指定的属性
Field getDeclaredField("属性名");
获取构造函数
获取类的所有公共构造函数
Constructor[] getConstructors();
获取类的所有构造函数
Constructor[] getDeclaredConstructors();
获取类的指定构造函数
Constructor<?> getDeclaredConstructor(获取构造函数的参数列表的类对象列表);
获取方法
获取类中所有公共方法
Method[] getMethods();
注意:可以获取到父类提供的公共方法
获取类中所有方法
Method[] getDeclaredMethods();
注意:只能获取该类的所有方法
获取类中指定方法
Method getDeclaredMethod(String name, Class... p)
参数1: 方法名
参数2: 该方法形参列表对应的类对象列表
如:
public void test(double d,String s,int i){
}
Method 方法对象 = 类对象.getDeclaredMethod("test",
double.class,String.class,int.class);
获取注解
package demo01;
public class Test {
public static void main(String[] args) throws Exception {
Person p = new Person();
//获取类对象方式1
//使用实例对象.getClass();
Class class1 = p.getClass();
//获取类对象方式2
//使用类名.class;
Class class2 = Person.class;
//获取类对象方式3
//使用Class类提供的静态方法
//Class.forName("包名.类名");
Class class3 = Class.forName("demo01.Person");
//证明只有一个类对象
System.out.println(class1 == class2);
System.out.println(class2 == class3);
}
}
运行结果
package demo01;
public class Test01 {
public static void main(String[] args) throws Exception {
Class c = Person.class;
String name = c.getName();
System.out.println("获取类的全名称: " + name);
String simpleName = c.getSimpleName();
System.out.println("获取类名: " + simpleName);
//获取类加载器
//暂时没用,后期需要在项目中使用src下配置文件时
//可以使用类加载获取
ClassLoader loader = c.getClassLoader();
System.out.println("类加载器: " + loader);
//获取父类
Class superclass = c.getSuperclass();
System.out.println("父类: " + superclass);
Class[] interfaces = c.getInterfaces();
for (Class c0 : interfaces) {
System.out.println("实现的接口: " + c0.getName());
}
Package package0 = c.getPackage();
System.out.println("类所在的包: " + package0.getName());
//通过类对象创建该类的实例对象
//newInstance调用的是该类的无参构造
//注意1:如果该类中没有无参构造函数,那么此时方法将出现NoSuchMethodException异常
//注意2:如果该类的无参构造访问权限不足,此时方法将出现IllegalAccessException异常
Person p = (Person) c.newInstance();
System.out.println("通过类对象创建的类的实例对象: " + p);
}
}
运行结果
Field类
常用方法:
修改对象的属性值
void set(对象, 修改后的值);
获取对象的属性值
Object get(对象);
略过访问权限修饰符
void setAccessible(true);
获取属性名
String getName();
package demo01;
import java.lang.reflect.Field;
public class Test02 {
public static void main(String[] args) throws Exception {
Class c = Person.class;
//获取类的所有公共属性
//注意:可以获取到父类的公共属性
Field[] fields01 = c.getFields();
for (Field f : fields01) {
System.out.println("公共属性: " + f.getName());
}
//获取本类的所有属性
//注意:只能获取本类的所有属性
Field[] fields02 = c.getDeclaredFields();
for (Field f : fields02) {
System.out.println("所有属性: " + f.getName());
}
//获取父类的类对象
Class superclass = c.getSuperclass();
Field[] fields03 = superclass.getDeclaredFields();
for (Field f : fields03) {
System.out.println("父类所有属性: " + f.getName());
}
//获取指定的属性
Field field01 = c.getDeclaredField("age");
Person p = (Person) c.newInstance();
System.out.println("修改前: " + p);
//修改对象的属性值
//参数1:要修改的对象
//参数2:修改后的值
field01.set(p, 18);
System.out.println("修改后: " + p);
//获取对象的属性值
int age = (int) field01.get(p);
System.out.println("获取到的属性值为: " + age);
//获取指定的属性
Field field02 = c.getDeclaredField("name");
//略过访问权限修饰符
field02.setAccessible(true);
field02.set(p, "张三");
System.out.println("修改后: " + p);
}
}
运行结果
Constructor类
常用方法:
创建对象
T newInstance(实参列表);
略过访问权限修饰符
void setAccessible(true);
package demo01;
import java.lang.reflect.Constructor;
public class Test03 {
public static void main(String[] args) throws Exception {
Class c = Person.class;
//获取类的所有公共构造函数
//此处没有父类的构造函数,因为子类无法继承父类构造函数
Constructor[] constructors01 = c.getConstructors();
for (Constructor constructor : constructors01) {
System.out.println("公共构造函数: " + constructor);
}
//获取类的所有构造函数
Constructor[] constructors02 = c.getDeclaredConstructors();
for (Constructor constructor : constructors02) {
System.out.println("所有构造函数: " + constructor);
}
//获取公共空参构造函数
Constructor<Person> constructor01 = c.getDeclaredConstructor();
Person p01 = constructor01.newInstance();
System.out.println(p01);
//获取私有2参构造函数
Constructor<Person> constructor02 = c.getDeclaredConstructor(String.class, String.class);
constructor02.setAccessible(true);
Person p02 = constructor02.newInstance("张三", "男");
System.out.println(p02);
}
}
运行结果
Method类
常用方法:
作用:执行方法
Object invoke(Object obj, Object... args);
参数:
obj:执行该方法的对象
args:实参列表
返回值:
执行的方法的返回值
略过访问权限修饰符
void setAccessible(true);
package demo01;
import java.lang.reflect.Method;
public class Test04 {
public static void main(String[] args) throws Exception {
Class c = Person.class;
Person p = new Person();
//获取所有的公共方法
//可以获取到父类或实现接口的公共方法
Method[] methods01 = c.getMethods();
for (Method method : methods01) {
System.out.println("公共方法: " + method);
}
//获取本类的所有方法
Method[] methods02 = c.getDeclaredMethods();
for (Method method : methods02) {
System.out.println("所有方法: " + method);
}
//获取私有的eat方法
Method m01 = c.getDeclaredMethod("eat");
//略过访问权限修饰符
m01.setAccessible(true);
//执行方法
m01.invoke(p);
//获取指定的setName方法
Method m02 = c.getDeclaredMethod("setName", String.class);
//执行setName方法
m02.invoke(p, "张三");
System.out.println(p);
//获取getName方法
Method m03 = c.getDeclaredMethod("getName");
//执行方法
String name = (String) m03.invoke(p);
System.out.println(name);
}
}
运行结果
Annotation类
设计模式
简介
一套被反复使用,多数人知道,经过分类,代码设计经验的总结
简单的理解为: 设计模式就是解决固定问题的方案
相关书籍: Gof的<<设计模式>>一共有23种设计模式
设计模式法则
单一职责: 一个方法或接口或类...只干一件事
开闭原则: 对扩展开放,对修改关闭
里式替换
依赖倒置
接口隔离
迪米特法则
单例模式
解决的问题:
让一个类只能产生一个对象
分类:
饿汉式
步骤:
1.私有构造函数,此时外部就无法通过new调用构造函数创建对象
2.在该类中提供一个私有的静态的不可修改的该类对象
3.提供公共静态方法,该方法返回步骤2的对象
以后外部需要该类对象只能使用类名.步骤3提供的静态方法得到
优点: 线程安全
缺点: 浪费内存
懒汉式
线程不安全
步骤:
1.私有构造函数
2.在该类中声明一个私有的静态的该类对象
3.提供公共静态方法,方法中
判断步骤2的对象是否为空,如果为空创建对象,赋值给该属性,再返回该类对象,如果不为空直接返回
优点:不浪费内存
缺点:只能应用于单线程情况下
线程安全的
使用锁
步骤:
1.私有构造函数
2.在该类中声明一个私有的静态的该类对象
3.提供同步的公共静态方法,方法中
判断步骤2的对象是否为空,如果为空创建对象,赋值给该属性,再返回该类对象,如果不为空直接返回
优点:不浪费内存,线程安全
缺点:在多线程的情况下比饿汉式效率低
静态内部类模式
工厂模式
解决的问题:
一个方法只能产生一种对象
例子:
一个家具厂通过制作方法可以制作椅子,桌子,衣柜,茶几等
枚举(了解)
作用: 限定值的取值范围
注意:
枚举是一种引用数据类型
枚举变量的值必须是枚举常量
枚举中可以定义普通的属性,方法与私有的构造函数
如果枚举中只有枚举常量,此时可以忽略分号不写,多个枚举常量直接使用逗号隔开
如果枚举中定义了普通属性等,此时枚举常量最后需要使用分号
枚举的定义:
访问权限修饰符 enum 枚举名{
枚举常量名1,枚举常量名2,...
}
枚举的使用:
声明变量
作为形参