답변:
두 방법을 어떻게 사용하는지 보여주는 예가 더 잘 이해하는 데 도움이 될 것입니다. 따라서 다음 클래스를 고려하십시오.
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)
Class
test.Demo.class
clazz
Class
그런 다음 호출 하면이 객체가 나타내는 클래스의 새 인스턴스가 생성됩니다 . 빈 인수 목록이 있는 표현식 으로 클래스가 인스턴스화됩니다 . 다시 말해, 이것은 여기서 실제로 a 와 동일하며 의 새 인스턴스를 반환합니다 .clazz.newInstance()
Class
new
new Demo()
Demo
이 Demo
클래스를 실행 하면 다음과 같은 출력이 출력됩니다.
Hi!
기존과의 큰 차이점 new
은 newInstance
런타임까지 알지 못하는 클래스를 인스턴스화하여 코드를 더 동적으로 만들 수 있다는 것입니다.
일반적인 예는 런타임시 작업 수행에 필요한 정확한 드라이버를로드하는 JDBC API입니다. EJB 컨테이너, 서블릿 컨테이너는 다른 좋은 예입니다. 동적 런타임 로딩을 사용하여 런타임 전에 알지 못하는 구성 요소를로드하고 만듭니다.
실제로 더 나아가고 싶다면 Ted Neward paper Understanding Class.forName () 에서 위의 단락에서 설명하고 있는 것을 살펴보십시오 .
편집 (의견으로 게시 된 OP의 질문에 답변) : JDBC 드라이버의 경우는 약간 특별합니다. JDBC API 시작하기 의 DriverManager 장에 설명 된대로 :
(...)
Driver
클래스가로드되어 다음DriverManager
두 가지 방법 중 하나로 자동으로 등록됩니다 .
메소드를 호출하여
Class.forName
. 드라이버 클래스를 명시 적으로로드합니다. 외부 설정에 의존하지 않기 때문에DriverManager
프레임 워크 를 사용하기 위해 드라이버를로드하는이 방법이 권장 됩니다. 다음 코드는 클래스를로드합니다acme.db.Driver
.Class.forName("acme.db.Driver");
경우
acme.db.Driver
그 로딩이 생성 될 인스턴스를 발생시키고 또한 호출 있도록 기록 된DriverManager.registerDriver
매개 변수로 해당 인스턴스와 함께 (그것이 무엇을해야으로), 그런 다음에DriverManager
드라이버의 목록과 연결을 만드는 데 사용할.(...)
이 두 경우 모두을
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 향상을 참조하십시오 .
DriverManager.registerDriver
. Class.forName
JDBC 드라이버를 호출 하면 초기화되어 정적 블록이 실행됩니다. 예제 는 java2s.com/Open-Source/Java-Document/Database-DBMS/… 를 보십시오 . 따라서 이것은 실제로 드라이버 내부로 인해 특별한 경우입니다.
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-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 () 메서드를 몇 번 호출하더라도 정적 블록이 여러 번 실행되지 않는 경우에만 :
패키지 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
진술은 세 번이 아니라 한 번만 인쇄됩니다.
Class.forName ()-> forName ()은 사용자 클래스 객체가 아닌 리플렉션에 사용되는 클래스 클래스 객체를 반환하므로 getMethods (), getConstructors () 등의 클래스 클래스 메소드 만 호출 할 수 있습니다.
(런타임 제공) 클래스의 정적 블록을 실행하고 클래스의 메소드, 생성자, 수정 자 등의 정보 만 얻는 것에 관심이 있다면 Class.forName ()을 사용 하여이 객체로 할 수 있습니다
그러나 클래스 메소드 (런타임에 제공 한 클래스)에 액세스하거나 호출하려면 클래스 클래스의 newInstance 메소드가 수행 할 수 있도록 객체가 있어야합니다. 클래스의 새 인스턴스를 작성하여 반환합니다. 클래스에 타입 캐스팅 만하면됩니다.
예 : 직원이 클래스라고 가정
클래스 a = Class.forName (args [0]);
// args [0] = cmd 라인 인수로 런타임에 클래스를 제공합니다.
직원 ob1 = a.newInstance ();
a.newInstance ()는 new Employee ()를 사용하여 객체를 만드는 것과 유사합니다.
이제 모든 클래스 표시 필드 및 메소드에 액세스 할 수 있습니다.