1.反射,泛型

1.2.1 反射机制

Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。

1.2.2 内置Class实例和数组的生命周期

Class的生命周期:

http://t.csdnimg.cn/TsmMa

数组的生命周期:
1.创建阶段:当程序中创建一个数组时,JVM会在堆内存中分配一块连续的内存空间来存储数组元素,并将数组的引用存放在栈内存中。
2使用阶段:在程序运行过程中,可以通过数组的引用来访问和操作数组元素,包括读取和修改元素的值。
3回收阶段:当数组不再被引用时,JVM会通过垃圾回收器来自动回收数组所占用的内存空间,释放资源。

1.2.3 反射与设计模式结合

1.工厂模式(Factory Pattern): 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。Java反射可以动态地创建对象,因此可以与工厂模式结合使用,实现更加灵活的对象创建。

// 定义一个接口
public interface Shape {
    void draw();
}

// 定义具体的实现类
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing Rectangle");
    }
}

// 定义工厂类
public class ShapeFactory {
    public static Shape createShape(String shapeType) {
        try {
            Class<?> clazz = Class.forName(shapeType);
            return (Shape) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

// 使用工厂类创建对象
public class FactoryPatternExample {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.createShape("com.example.Circle");
        circle.draw();

        Shape rectangle = ShapeFactory.createShape("com.example.Rectangle");
        rectangle.draw();
    }
}

2.单例模式(Singleton Pattern): 单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。通过Java反射,可以破坏单例模式的封装性,因此在使用反射时需要特别注意单例模式的实现。

// 单例类
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}

// 使用反射获取单例对象
public class SingletonReflectionExample {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();

        try {
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton instance2 = constructor.newInstance();
            
            System.out.println(instance1 == instance2); // 输出false,破坏了单例模式
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.代理模式(Proxy Pattern): 代理模式是一种结构型设计模式,它允许通过代理类来控制对目标对象的访问。Java反射可以动态地创建代理对象,从而与代理模式结合使用。

// 定义接口
public interface Image {
    void display();
}

// 定义真实对象
public class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }

    private void loadFromDisk() {
        System.out.println("Loading " + filename + " from disk");
    }
}

// 定义代理类
public class ImageProxy implements Image {
    private String filename;
    private RealImage realImage;

    public ImageProxy(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 使用代理类
public class ProxyPatternExample {
    public static void main(String[] args) {
        Image image = new ImageProxy("test.jpg");
        image.display();
    }
}

4策略模式(Strategy Pattern): 策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。Java反射可以动态地选择和应用不同的策略,从而与策略模式结合使用。

// 定义策略接口
interface PaymentStrategy {
    void pay(int amount);
}

// 定义具体的策略类
class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("Paid " + amount + " using credit card");
    }
}

class PayPalPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("Paid " + amount + " using PayPal");
    }
}

// 定义上下文类
class PaymentContext {
    private PaymentStrategy strategy;

    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void pay(int amount) {
        strategy.pay(amount);
    }
}

// 使用策略模式
public class StrategyPatternExample {
    public static void main(String[] args) {
        PaymentStrategy creditCardPayment = new CreditCardPayment();
        PaymentStrategy payPalPayment = new PayPalPayment();

        PaymentContext context1 = new PaymentContext(creditCardPayment);
        context1.pay(100);

        PaymentContext context2 = new PaymentContext(payPalPayment);
        context2.pay(200);
    }
}

5观察者模式(Observer Pattern): 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。Java反射可以动态地注册和通知观察者对象,从而与观察者模式结合使用。

import java.util.ArrayList;
import java.util.List;

// 定义观察者接口
interface Observer {
    void update(String message);
}

// 定义主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

// 定义具体的主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// 定义具体的观察者类
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// 使用观察者模式
public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
        ConcreteObserver observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.notifyObservers("Hello, observers!");
    }
}

1.3.1 Java自动装箱拆箱

为什么要设计自动装箱和自动拆箱呢?这样设计的好处在于简化了代码编写过程,提高了代码的可读性和易用性。在使用自动装箱和自动拆箱的情况下,可以直接将基本类型和对应的包装类型进行混合使用,而不需要过多地关注类型转换的细节。

另外,自动装箱和自动拆箱也使得泛型和集合类的使用更加便捷。例如,可以直接将基本类型的值放入集合中,而不需要手动进行类型转换。

1.3.2 泛型的使用

泛型(Generics)是一种参数化类型的概念,它允许我们在定义类、接口和方法时使用类型参数,从而使得这些类、接口和方法能够操作各种不同类型的数据,而不需要进行类型转换。泛型的使用可以提高代码的重用性、可读性和类型安全性。

泛型的基本语法包括使用尖括号<>来声明类型参数,通常用大写字母来表示类型参数。例如,表示一个泛型类型参数,可以在类、接口或方法的声明中使用。

下面是一些常见的泛型使用方式:
在类中使用泛型:

public class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

在接口中使用泛型:

public interface List<T> {
    void add(T value);
    T get(int index);
}

在方法中使用泛型:

public <T> T getValue(T[] array, int index) {
    return array[index];
}

泛型的使用可以提高代码的灵活性和安全性,避免了类型转换的繁琐和可能导致的运行时异常
示例:

public class GenericBoxExample {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>(10);
        int value = intBox.getValue();  // 不需要进行类型转换
        System.out.println(value);

        Box<String> stringBox = new Box<>("Hello");
        String str = stringBox.getValue();
        System.out.println(str);
    }
}

class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

1.3.3 泛型的类型擦除

泛型是在编译时期进行类型检查的,但在运行时会被擦除。这意味着在运行时,泛型类型信息会被擦除,而只保留原始类型的信息。这种设计是为了向后兼容旧版本的Java,并且使得泛型可以在不同类型之间进行转换。

具体来说,泛型类型信息在编译时会被擦除,而在运行时只能获取到原始类型的信息。例如,对于泛型类List,在运行时只能获取到List,而无法获取到List的信息。

这种类型擦除的设计有以下几个影响和好处:

向后兼容性:类型擦除使得支持泛型的类可以与旧版本的Java代码兼容,因为在运行时泛型信息已经被擦除。
减少重复信息:类型擦除减少了在运行时存储和传递泛型类型信息的开销,从而提高了性能和减少了内存占用。
简化编译后的代码:类型擦除使得编译后的代码更加简洁,因为泛型信息被擦除后,编译器不需要生成额外的类型信息。

举例:

public class GenericTypeErasureExample {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("Hello");
        String value = stringList.get(0);  // 在运行时,只能获取到原始类型List的信息
        System.out.println(value);
    }
}

在上面的例子中,尽管在编译时使用了List类型,但在运行时只能获取到List类型的信息。这就是泛型类型擦除的影响之一。需要注意的是,尽管泛型类型信息在运行时被擦除,但是在编译时仍然会进行类型检查,以确保类型安全性。

java泛型详细

你可能感兴趣的:(java)