反射及部分设计模式
一、反射 (通用编程)
1. 概念
允许在程序运行状态中,可以获取任意类中的属性和方法,并且可以操作任意对象内部的属性和方法,这种动态获取类的信息及动态操作对象的属性和方法对应的机制称为反射机制。
2. 类的对象 和 类对象
(1) 类的对象:基于定义好的类,创建的该类对象、实例
(new 的对象)
(2) 类对象:类加载的产物,封装类该类信息(包名、类名、
父类、接口、属性、构造方法、成员方法等)。
类加载:JVM第一次使用一个类的时候,通过 classPath找到该类对应.class文件,读取.class文件,读取该类信息(包名、类名、父类、接口、属性、成员方法、构造 方法等信息),将该信息保存在jvm中,类加载进行一次。
类加载时机:
a. 第一次创建该类对象
b. 第一次使用该类静态成员
c. 加载子类会先加载其父类
d. 通过反射技术获取类对象
3. 获取类对象的方式 【重点】
(1) 通过 类的对象 获取 类对象,getClass方法
Student s = new Student();
Class c1 =s.getClass();
(2) 通过 类名.class 获取类对象
Class c2 = Student.class;
(3)利用Class类中静态方法forName(String className);
Class c3 =Class.forName(“包名.类名”);
注意:forName方法中参数需要的是全类名,否则运行报错,错误信息ClassNotFoundException(类找不到的异常)
4. Class中的成员方法
package classtest4;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestClass1 {
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("day33.Student");
// 通过类对象获取对应类信息
System.out.println(c.getName()); // 获取类名
System.out.println(c.getPackage().getName());// 获取包名
System.out.println(c.getSuperclass().getName()); // 获取父类名
Class[] inters = c.getInterfaces(); // 获取所有实现的接口
System.out.println("实现接口的个数:" + inters.length);
for (Class inter : inters) {
System.out.println(inter.getName());
}
System.out.println("---------获取属性---------");
Field[] fs = c.getFields();// 获取 公开属性(父类+子类的公开属性)
System.out.println("类中属性的个数:" + fs.length);
Field[] fs2 = c.getDeclaredFields(); // 获取自定义的属性:公开+非公开的属性
System.out.println("类中属性个数:" + fs2.length);
System.out.println("---------------------------------");
Method[] ms = c.getMethods();// 获取公开方法:本类+父类的
System.out.println("类中方法的个数:" + ms.length);
for (Method m : ms) {
System.out.println(m.getName());
}
// 获取自己定义方法:包含非公开的
Method[] ms2 = c.getDeclaredMethods();
System.out.println("------类中自己定义的方法具体内容------");
for (Method m : ms2) {
System.out.println(m.getName());
}
}
}
二、设计模式(23种)
1.概念
是一套被反复使用,多数人知晓、经过分类编目的代码经验总结
2.适配器设计模式
用一个或多个抽象类去分别实现接口中某些需要的方法,然后再用实现类去将抽象类中的方法进行覆盖或实现,这样既可以弱耦合,而且便于分类和管理
3.单例设计模式
(1)概念
定义一个类,保证jvm中只有该类的一个实例对象存在
(2)代码实现单例模式:
a.饿汉式
优点:并发效率较高
缺点:空间利用率相对较低
package classtest4;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestHungry {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 1; i <= 100; i++) {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<B> f1 = pool.submit(new Callable<B>() {
public B call() {
return B.getInstance();
}
});
Future<B> f2 = pool.submit(new Callable<B>() {
public B call() {
return B.getInstance();
}
});
try {
B b1 = f1.get();
B b2 = f2.get();
if (i == 1)
System.out.println(b1 == b2 ? "两个线程获取的是同一对象" : "两个线程获取的是不同对象");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
pool.shutdown();
}
}
long end = System.currentTimeMillis();
System.out.println("程序运行时间:" + (end - start) + "ms");
}
}
class B {
private static final B B = new B();
private B() {
}
public static B getInstance() {
return B;
}
}
b.懒汉式
优点:空间利用率相对较高
缺点:并发效率相对较低,因为方法被synchronized修饰
package classtest4;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestLazy {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 1; i <= 100; i++) {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<A> f1 = pool.submit(new Callable<A>() {
public A call() {
return A.getInstance();
}
});
Future<A> f2 = pool.submit(new Callable<A>() {
public A call() {
return A.getInstance();
}
});
try {
A a1 = f1.get();
A a2 = f2.get();
if (i == 1)
System.out.println(a1 == a2 ? "两个线程获取的是同一对象" : "两个线程获取的是不同对象");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
pool.shutdown();
}
}
long end = System.currentTimeMillis();
System.out.println("程序运行时间:" + (end - start) + "ms");
}
}
class A {
private static A A;
private A() {
}
public static synchronized A getInstance() {
if (A == null) {
A = new A();
}
return A;
}
}
经过数十次的运行,发现 懒汉式运行时间大致分布为37-49 饿汉式运行时间大致为36-64,不过结果也不是太准确,如果有兴趣的,可以多整几个线程去测试一下它们两个之间的效果
c.用内部类实现的单例
package classtest4;
public class TestSingle {
public static void main(String[] args) {
Object o1 = Single.getInstance();
Object o2 = Single.getInstance();
System.out.println(o1 == o2 ? "相同对象" : "不同对象");
}
}
class Single {
private Single() {
}
static class Inner {
private static final Single S = new Single();
}
public static Single getInstance() {
return Inner.S;
}
}
特点: 空间利用率高,并发效率高
4.工厂设计模式
(1)主要解决的问题:对象的创建,工厂的职责就在于创建一个对象
(2)工厂设计模式结合反射技术,使代码更加的通用和灵活
(3)扩充: Properties,Map集合的实现类,键值对存储
a.load(FileInputStream/FileReader in):将输入流指向的文件中内容加载到Properties中,文件中一行内容对应Properties一个键值对元素的内容自动以"=“进行拆分,”=“左侧为键,”="右侧为值
b.getProperty(String key):根据键获取对应的值
package classtest4;
import java.io.FileInputStream;
import java.util.Properties;
public class TestFactory {
public static void main(String[] args) throws Exception {
// 创建电脑对象
Computer c = new Computer();
USB usb = USBFactory.getUSBInstance();
c.useDevice(usb);
}
}
// 工厂类(结合反射让程序更加的灵活和通用)
class USBFactory {
public static USB getUSBInstance() throws Exception {
Properties pro = new Properties();
FileInputStream fis = new FileInputStream("config.txt");
pro.load(fis);
String value = pro.getProperty("className");
Class<?> c = Class.forName(value);
// 通过类对象 获取 类的对象
Object obj = c.newInstance();
return (USB) obj;
}
}
// A类 使用者
class Computer {
public void useDevice(USB usb) {
usb.service();
}
}
// 对电子设备 和 电脑做一个标准和规范(接口)
interface USB {
void service();
}
// B类 鼠标
class Mouse implements USB {
public void service() {
System.out.println("鼠标...");
}
}
// C类 键盘
class Keyboard implements USB {
public void service() {
System.out.println("键盘...");
}
}