[java] “Class.forName ()”과“Class.forName (). newInstance ()”의 차이점은 무엇입니까?

차이점은 무엇이며 Class.forName()그리고 Class.forName().newInstance()?

나는 중요한 차이점을 이해하지 못한다 (나는 그들에 대해 뭔가를 읽었다!). 저 좀 도와 주 시겠어요?



답변

두 방법을 어떻게 사용하는지 보여주는 예가 더 잘 이해하는 데 도움이 될 것입니다. 따라서 다음 클래스를 고려하십시오.

package test;

public class Demo {

    public Demo() {
        System.out.println("Hi!");
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("test.Demo");
        Demo demo = (Demo) clazz.newInstance();
    }
}

javadoc에 설명 된대로 호출 주어진 문자열 이름을 가진 클래스 또는 인터페이스와 연관된 객체를 리턴합니다. 즉 , 유형 의 변수에 영향을 주는 객체를 리턴합니다 .Class.forName(String) Classtest.Demo.classclazzClass

그런 다음 호출 하면이 객체가 나타내는 클래스의 새 인스턴스가 생성됩니다 . 빈 인수 목록이 있는 표현식 으로 클래스가 인스턴스화됩니다 . 다시 말해, 이것은 여기서 실제로 a 와 동일하며 의 새 인스턴스를 반환합니다 .clazz.newInstance() Classnewnew Demo()Demo

Demo클래스를 실행 하면 다음과 같은 출력이 출력됩니다.

Hi!

기존과의 큰 차이점 newnewInstance런타임까지 알지 못하는 클래스를 인스턴스화하여 코드를 더 동적으로 만들 수 있다는 것입니다.

일반적인 예는 런타임시 작업 수행에 필요한 정확한 드라이버를로드하는 JDBC API입니다. EJB 컨테이너, 서블릿 컨테이너는 다른 좋은 예입니다. 동적 런타임 로딩을 사용하여 런타임 전에 알지 못하는 구성 요소를로드하고 만듭니다.

실제로 더 나아가고 싶다면 Ted Neward paper Understanding Class.forName () 에서 위의 단락에서 설명하고 있는 것을 살펴보십시오 .

편집 (의견으로 게시 된 OP의 질문에 답변) : JDBC 드라이버의 경우는 약간 특별합니다. JDBC API 시작하기DriverManager 장에 설명 된대로 :

(…) Driver클래스가로드되어 다음 DriverManager두 가지 방법 중 하나로 자동으로 등록됩니다 .

  1. 메소드를 호출하여 Class.forName. 드라이버 클래스를 명시 적으로로드합니다. 외부 설정에 의존하지 않기 때문에 DriverManager
    프레임 워크 를 사용하기 위해 드라이버를로드하는이 방법이 권장 됩니다. 다음 코드는 클래스를로드합니다 acme.db.Driver.

    Class.forName("acme.db.Driver");

    경우 acme.db.Driver그 로딩이 생성 될 인스턴스를 발생시키고 또한 호출 있도록 기록 된
    DriverManager.registerDriver매개 변수로 해당 인스턴스와 함께
    (그것이 무엇을해야으로), 그런 다음에
    DriverManager드라이버의 목록과 연결을 만드는 데 사용할.

  2. (…)

이 두 경우 모두을 Driver호출 하여 새로로드 된 클래스가 자신을 등록해야합니다 DriverManager.registerDriver. 언급했듯이 이것은 클래스가로드 될 때 자동으로 수행되어야합니다.

초기화 중에 스스로 등록하기 위해 JDBC 드라이버는 일반적으로 다음과 같은 정적 초기화 블록을 사용합니다.

package acme.db;

public class Driver {

    static {
        java.sql.DriverManager.registerDriver(new Driver());
    }

    ...
}

호출 Class.forName("acme.db.Driver")하면 acme.db.Driver클래스 가 초기화 되어 정적 초기화 블록이 실행됩니다. 그리고 Class.forName("acme.db.Driver")실제로 인스턴스를 “생성”할 것입니다. 이것은 단지 (좋은) JDBC 드라이버가 구현 된 결과 일뿐입니다.

참고로, JDBC 4.0 (Java 7 이후 기본 패키지로 추가)과 JDBC 4.0 드라이버의 새로운 자동 로딩 기능에는이 모든 것이 더 이상 필요하지 않다고 언급했습니다. Java SE 6의 JDBC 4.0 향상을 참조하십시오 .


답변

Class.forName ()은 리플렉션에 유용한 클래스 객체를 제공합니다. 이 객체가 가진 메소드는 프로그래머가 클래스를 작성하는 것이 아니라 Java에 의해 정의됩니다. 그들은 모든 수업에서 동일합니다. newInstance ()를 호출 Class.forName("ExampleClass").newInstance()하면 해당 클래스의 인스턴스를 제공합니다 (즉, 호출 과 동일 함 new ExampleClass()). 클래스에서 정의하는 메소드를 호출하고 표시되는 필드에 액세스하는 등의 작업을 수행 할 수 있습니다.


답변

JDBC 세계에서 일반적인 방법 (JDBC API에 따름)은 Class#forName()JDBC 드라이버를로드하는 데 사용하는 것 입니다. JDBC 드라이버는 DriverManager정적 블록 내부에 자체 등록해야합니다 .

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class MyDriver implements Driver {

    static {
        DriverManager.registerDriver(new MyDriver());
    }

    public MyDriver() {
        //
    }

}

호출하면 Class#forName()모든 정적 이니셜 라이저 가 실행됩니다 . 이 방법은 DriverManager연결 URL을 통해 등록 된 드라이버 중에서 관련 드라이버를 찾을 수있는 동안 getConnection()대략 다음과 같습니다.

public static Connection getConnection(String url) throws SQLException {
    for (Driver driver : registeredDrivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url);
        }
    }
    throw new SQLException("No suitable driver");
}

그러나 잘 알려진 예제 부터 시작하여 버그가있는 JDBC 드라이버 도있었습니다.이 드라이버 는 정적 블록 대신 생성자org.gjt.mm.mysql.Driver 내에 자신을 잘못 등록합니다 .

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class BadDriver implements Driver {

    public BadDriver() {
        DriverManager.registerDriver(this);
    }

}

동적으로 작동하게하는 유일한 방법은 newInstance()나중에 전화하는 것입니다 ! 그렇지 않으면 언뜻 설명 할 수없는 “SQLException : no driver”가 표시됩니다. 다시 한 번, 이것은 자신의 코드가 아닌 JDBC 드라이버 의 버그 입니다. 요즘에는 JDBC 드라이버에이 버그가 없어야합니다. 그래서 당신은 newInstance()멀리 떠날 수 있습니다.


답변

1 : 클래스의 정적 블록에만 관심이 있다면 클래스로드 만 할 것이고 정적 블록을 실행하면 필요한 것은 다음과 같습니다.

Class.forName("Somthing");

2 : 클래스로드에 관심이 있고 정적 블록을 실행하고 정적이 아닌 부분에 액세스하려면 인스턴스가 필요하며 다음이 필요합니다.

Class.forName("Somthing").newInstance();


답변

Class.forName ()은 클래스에 대한 참조를 가져옵니다. Class.forName (). newInstance ()는 클래스에 대해 인수 없음 생성자를 사용하여 새 인스턴스를 리턴하려고합니다.


답변

“Class.forName ()”은 주어진 이름에 대한 Class-Type을 반환합니다. “newInstance ()”는이 클래스의 인스턴스를 반환합니다.

유형에서는 인스턴스 메소드를 직접 호출 할 수 없지만 클래스에 대해서만 리플렉션을 사용할 수 있습니다. 클래스의 객체로 작업하려면 “new MyClass ()”호출과 같은 인스턴스를 만들어야합니다.

“Class.forName ()”의 예

Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);

“Class.forName (). newInstance ()”의 예

MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());


답변

메모리에 있어야하는 정적 코드 (예 : 코드 블록은 인스턴스와 무관)가있을 때 위의 답변에 추가하면 클래스를 반환하여 Class.forname ( “someName”)을 사용할 수 있습니다. 정적 코드를 가지고 있지 않습니다. Class.forname (). newInstance ( “someName”)은 객체 레벨 코드 블록 (비 정적)을 메모리에로드 할 수 있습니다.