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


165

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

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

답변:


247

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

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 향상을 참조하십시오 .


하지만 여전히이 사이트에 있습니다 : java.sun.com/docs/books/tutorial/jdbc/basics/connecting.html
Johanna

2
"Class.forName을 호출하면 드라이버의 인스턴스가 자동으로 생성되어 DriverManager에 등록되므로 클래스의 인스턴스를 만들 필요가 없습니다. 자신의 인스턴스를 만들려면 , 불필요한 복제본을 만들지 만 해를 끼치 지 않습니다. " 이는 Class.forName에 의해 비정상적으로 인스턴스를 작성하고 다른 인스턴스를 작성하려는 경우 불필요한 인스턴스를 작성하므로 Calss.forName () 및 Class.forName (). newInstance () 모두 인스턴스를 작성 함을 의미합니다. 운전사!!
Johanna

10
JDBC 드라이버는 "특별"하며 인스턴스가 생성되고 매개 변수로 전달되는 정적 초기화 블록으로 작성됩니다 DriverManager.registerDriver. Class.forNameJDBC 드라이버를 호출 하면 초기화되어 정적 블록이 실행됩니다. 예제 는 java2s.com/Open-Source/Java-Document/Database-DBMS/… 를 보십시오 . 따라서 이것은 실제로 드라이버 내부로 인해 특별한 경우입니다.
Pascal Thivent

1
나는에 나타났습니다 다른 답변 ,에 Class.newInstance ()를 사용하는 것은 권장하지 않습니다. Class.getConstructor ()와 Constructor.newInstance ()를 차례로 사용하는 것이 좋습니다. 가능한 예외를 마스킹하지 않습니다.
LS

"newInstance를 사용하면 런타임까지 알 수없는 클래스를 인스턴스화 할 수 있습니다." 감사.
Code Enthusiastic

37

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


29

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()멀리 떠날 수 있습니다.


17

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

Class.forName("Somthing");

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

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

훌륭한 답변! 명확하고 간결합니다!
gaurav

6

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


3

"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());

3

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


1

Class.forName () 메서드를 몇 번 호출하더라도 정적 블록이 여러 번 실행되지 않는 경우에만 :

패키지 forNameMethodDemo;

공개 클래스 MainClass {

    public static void main(String[] args) throws Exception {
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        DemoClass demoClass = (DemoClass)Class.forName("forNameMethodDemo.DemoClass").newInstance();
    }

}

공공 수업 DemoClass {

static {
    System.out.println("in Static block");
}

{
    System.out.println("in Instance block");
}

}

출력은 다음과 같습니다.

in Static block in Instance block

in Static block진술은 세 번이 아니라 한 번만 인쇄됩니다.


0

Class.forName ()-> forName ()은 사용자 클래스 객체가 아닌 리플렉션에 사용되는 클래스 클래스 객체를 반환하므로 getMethods (), getConstructors () 등의 클래스 클래스 메소드 만 호출 할 수 있습니다.

(런타임 제공) 클래스의 정적 블록을 실행하고 클래스의 메소드, 생성자, 수정 자 등의 정보 만 얻는 것에 관심이 있다면 Class.forName ()을 사용 하여이 객체로 할 수 있습니다

그러나 클래스 메소드 (런타임에 제공 한 클래스)에 액세스하거나 호출하려면 클래스 클래스의 newInstance 메소드가 수행 할 수 있도록 객체가 있어야합니다. 클래스의 새 인스턴스를 작성하여 반환합니다. 클래스에 타입 캐스팅 만하면됩니다.

예 : 직원이 클래스라고 가정

클래스 a = Class.forName (args [0]);

// args [0] = cmd 라인 인수로 런타임에 클래스를 제공합니다.

직원 ob1 = a.newInstance ();

a.newInstance ()는 new Employee ()를 사용하여 객체를 만드는 것과 유사합니다.

이제 모든 클래스 표시 필드 및 메소드에 액세스 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.