JAVA 인터뷰 질문의 최신 모음 (5)

반사

57. 반사 란 무엇입니까?

반사는 주로 프로그램이 자신의 상태 또는 동작에 액세스, 감지 및 수정하는 기능을 나타냅니다.

자바 리플렉션 :

Java 런타임 환경에서 모든 클래스에 대해 클래스에 어떤 속성과 메소드가 있는지 알 수 있습니까? 모든 개체에 대해 해당 메서드를 호출 할 수 있습니다.

Java 리플렉션 메커니즘은 주로 다음 기능을 제공합니다.

  • 런타임에 객체가 속한 클래스를 판단합니다.

  • 런타임에 모든 클래스의 객체를 생성합니다.

  • 런타임에 모든 클래스의 멤버 변수와 메서드를 판단합니다.

  • 런타임에 모든 개체 메서드를 호출합니다.

58. 자바 직렬화 란 무엇입니까? 어떤 상황에서 직렬화가 필요합니까?

간단히 말해, 다양한 객체의 상태를 메모리 (즉, 메소드가 아닌 인스턴스 변수)에 저장하고 저장된 객체 상태를 읽는 것입니다. 사용자 자신의 다양한 방법을 사용하여 객체 상태를 저장할 수 있지만 Java는 자신보다 나은 객체 상태 저장 메커니즘 인 직렬화를 제공합니다.

직렬화가 필요한 상황 :

a) 메모리의 객체 상태를 파일 또는 데이터베이스에 저장하고
싶을 때 b) 소켓을 사용하여 네트워크에서
객체를 전송하려는 경우 c) RMI를 통해 객체를 전송하려는 경우 ;

59. 동적 에이전트 란 무엇입니까? 응용 프로그램은 무엇입니까?

동적 프록시 :

특정 인터페이스를 구현하는 클래스의 메서드에 추가 처리를 추가하려는 경우. 예를 들어 로그 추가, 트랜잭션 추가 등이 있습니다. 이 클래스에 대한 프록시를 만들 수 있으므로 이름에서 알 수 있듯이 새 클래스를 만드는 것입니다.이 클래스는 원래 클래스 메서드의 기능을 포함 할뿐만 아니라 원래 기준으로 추가 처리를 통해 새 클래스를 추가합니다. 이 프록시 클래스는 잘 정의되어 있지 않으며 동적으로 생성됩니다. 디커플링, 유연성 및 강력한 확장 성의 의미가 있습니다.

동적 에이전트의 적용 :

  • Spring 的 AOP

  • 업무 추가

  • 권한 추가

  • 로그 추가

60. 동적 프록시를 구현하는 방법은 무엇입니까?

먼저 인터페이스를 정의하고 InvocationHandler (인터페이스를 구현하는 클래스의 개체를 전달) 처리 클래스를 정의해야합니다. 또 다른 도구 클래스 Proxy가 있습니다 (그의 newInstance ()를 호출하면 프록시 객체를 생성 할 수 있기 때문에 프록시 클래스라고 부르는 것이 일반적입니다. 사실 프록시 객체를 생성하는 도구 클래스 일뿐입니다). InvocationHandler를 사용하여 프록시 클래스의 소스 코드를 스 플라이 싱하고, 프록시 클래스의 이진 코드를 생성하기 위해 컴파일하고, 로더로로드하고, 프록시 객체를 생성하기 위해 인스턴스화하고, 마지막으로 반환합니다.


개체 복사

61. 복제를 사용하는 이유는 무엇입니까?

객체를 처리하고 싶지만 다음 작업을 위해 원본 데이터를 유지하려면 복제해야합니다. Java 언어로 된 복제는 클래스 인스턴스 용입니다.

62. 개체 복제를 구현하는 방법은 무엇입니까?

두 가지 방법이 있습니다.

1) Cloneable 인터페이스를 구현하고 Object 클래스에서 clone () 메서드를 다시 작성합니다.

2) Serializable 인터페이스를 실현하고, 실제 딥 클론을 실현할 수있는 객체의 직렬화 및 역 직렬화를 통해 클론을 실현합니다. 코드는 다음과 같습니다.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyUtil {
    
    

    private MyUtil() {
    
    
        throw new AssertionError();
    }

    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) throws Exception {
    
    
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bout);
        oos.writeObject(obj);

        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bin);
        return (T) ois.readObject();

        // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
        // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
    }
}

다음은 테스트 코드입니다.


import java.io.Serializable;

/**
 * 人类
 * @author nnngu
 *
 */
class Person implements Serializable {
    
    
    private static final long serialVersionUID = -9102017020286042305L;

    private String name;    // 姓名
    private int age;        // 年龄
    private Car car;        // 座驾

    public Person(String name, int age, Car car) {
    
    
        this.name = name;
        this.age = age;
        this.car = car;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
    }

}
/**
 * 小汽车类
 * @author nnngu
 *
 */
class Car implements Serializable {
    
    
    private static final long serialVersionUID = -5713945027627603702L;

    private String brand;       // 品牌
    private int maxSpeed;       // 最高时速

    public Car(String brand, int maxSpeed) {
    
    
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
    
    
        return brand;
    }

    public void setBrand(String brand) {
    
    
        this.brand = brand;
    }

    public int getMaxSpeed() {
    
    
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
    
    
        this.maxSpeed = maxSpeed;
    }

    @Override
    public String toString() {
    
    
        return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
    }

}
class CloneTest {
    
    

    public static void main(String[] args) {
    
    
        try {
    
    
            Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
            Person p2 = MyUtil.clone(p1);   // 深度克隆
            p2.getCar().setBrand("BYD");
            // 修改克隆的Person对象p2关联的汽车对象的品牌属性
            // 原来的Person对象p1关联的汽车不会受到任何影响
            // 因为在克隆Person对象时其关联的汽车对象也被克隆了
            System.out.println(p1);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

참고 : 직렬화 및 역 직렬화를 기반으로 한 복제는 딥 복제 일뿐만 아니라 더 중요한 것은 복제 할 객체가 직렬화를 지원하는지 여부를 일반 제한을 통해 확인할 수 있다는 것입니다.이 검사는 런타임에 예외가 발생하는 것이 아니라 컴파일러에 의해 수행됩니다. 이 솔루션은 Object 클래스의 clone 메서드를 사용하여 개체를 복제하는 것보다 분명히 낫습니다. 런타임에 문제를 남기는 것보다 컴파일 타임에 문제를 노출하는 것이 항상 낫습니다.

63. 딥 카피와 얕은 카피의 차이점은 무엇입니까?

  • 단순 복사는 객체의 참조 주소 만 복사하고 두 객체는 ​​동일한 메모리 주소를 가리 키므로 값이 수정되면 다른 값도 그에 따라 변경됩니다. 이것은 단순 복사입니다 (예 : assign ()).

  • 전체 복사는 객체와 값을 복사하는 것입니다. 두 객체는 ​​다른 값의 값을 변경하지 않습니다. 이는 전체 복사 (예 : JSON.parse () 및 JSON.stringify ())이지만이 메서드는 함수를 복사 할 수 없습니다. 유형)

추천

출처blog.csdn.net/weixin_42120561/article/details/114695345