Câu trả lời:
Có thể một ví dụ minh họa cách cả hai phương pháp được sử dụng sẽ giúp bạn hiểu mọi thứ tốt hơn. Vì vậy, hãy xem xét các lớp sau:
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();
}
}
Như đã giải thích trong javadoc của nó, việc gọi trả về đối tượng được liên kết với lớp hoặc giao diện với tên chuỗi đã cho tức là nó trả về bị ảnh hưởng đến biến kiểu .Class.forName(String)
Class
test.Demo.class
clazz
Class
Sau đó, việc gọi tạo một thể hiện mới của lớp được đại diện bởi đối tượng này . Lớp được khởi tạo như thể bởi một biểu thức có danh sách đối số trống. Nói cách khác, đây thực sự là tương đương với a và trả về một thể hiện mới của .clazz.newInstance()
Class
new
new Demo()
Demo
Và chạy Demo
lớp này do đó in ra đầu ra sau:
Hi!
Sự khác biệt lớn với truyền thống new
là newInstance
cho phép khởi tạo một lớp mà bạn không biết cho đến khi chạy, làm cho mã của bạn năng động hơn.
Một ví dụ điển hình là API JDBC tải, trong thời gian chạy, trình điều khiển chính xác cần có để thực hiện công việc. Các thùng chứa EJB, các thùng chứa Servlet là những ví dụ điển hình khác: chúng sử dụng tải thời gian chạy động để tải và tạo các thành phần mà chúng không biết gì trước thời gian chạy.
Trên thực tế, nếu bạn muốn đi xa hơn, hãy xem bài viết của Ted Neward Hiểu về Class.forName () mà tôi đã diễn giải trong đoạn văn ở trên.
EDIT (trả lời một câu hỏi từ OP được đăng dưới dạng bình luận): Trường hợp trình điều khiển JDBC hơi đặc biệt. Như đã giải thích trong chương DriverManager về Bắt đầu với API JDBC :
(...) Một
Driver
lớp được tải và do đó tự động được đăng ký vớiDriverManager
, theo một trong hai cách:
bằng cách gọi phương thức
Class.forName
. Điều này rõ ràng tải lớp trình điều khiển. Vì nó không phụ thuộc vào bất kỳ thiết lập bên ngoài nào, nên cách tải trình điều khiển này là cách được khuyến nghị để sử dụngDriverManager
khung. Đoạn mã sau tải lớpacme.db.Driver
:Class.forName("acme.db.Driver");
Nếu
acme.db.Driver
đã được viết để tải nó làm cho một cá thể được tạo và cũng gọiDriverManager.registerDriver
với cá thể đó là tham số (như nó nên làm), thì nó nằm trongDriverManager
danh sách các trình điều khiển và có sẵn để tạo kết nối.(...)
Trong cả hai trường hợp này, trách nhiệm của lớp mới được tải
Driver
là tự đăng ký bằng cách gọiDriverManager.registerDriver
. Như đã đề cập, điều này nên được thực hiện tự động khi lớp được tải.
Để tự đăng ký trong quá trình khởi tạo, trình điều khiển JDBC thường sử dụng khối khởi tạo tĩnh như thế này:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
Việc gọi Class.forName("acme.db.Driver")
gây ra việc khởi tạo acme.db.Driver
lớp và do đó thực hiện khối khởi tạo tĩnh. Và Class.forName("acme.db.Driver")
thực sự sẽ "tạo" một thể hiện nhưng đây chỉ là hệ quả của cách trình điều khiển JDBC (tốt) được triển khai.
Một lưu ý phụ, tôi muốn đề cập rằng tất cả những điều này không còn cần thiết nữa với JDBC 4.0 (được thêm dưới dạng gói mặc định kể từ Java 7) và tính năng tải tự động mới của trình điều khiển JDBC 4.0. Xem các cải tiến JDBC 4.0 trong Java SE 6 .
DriverManager.registerDriver
. Gọi Class.forName
trình điều khiển JDBC gây ra khởi tạo của nó và do đó thực thi khối tĩnh. Hãy xem java2s.com/Open-Source/Java-Document/Database-DBMS/iêu để lấy ví dụ. Vì vậy, đây thực sự là một trường hợp cụ thể do trình điều khiển bên trong.
Class.forName () cung cấp cho bạn đối tượng lớp, rất hữu ích cho việc phản chiếu. Các phương thức mà đối tượng này đã được xác định bởi Java, không phải bởi lập trình viên viết lớp. Chúng giống nhau cho mọi lớp học. Gọi newInstance () trên đó cung cấp cho bạn một thể hiện của lớp đó (tức là gọi Class.forName("ExampleClass").newInstance()
nó tương đương với gọi new ExampleClass()
), trên đó bạn có thể gọi các phương thức mà lớp định nghĩa, truy cập vào các trường hiển thị, v.v.
Trong thế giới JDBC, cách làm thông thường (theo API JDBC) là bạn sử dụng Class#forName()
để tải trình điều khiển JDBC. Trình điều khiển JDBC nên đăng ký chính nó DriverManager
trong một khối tĩnh:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class MyDriver implements Driver {
static {
DriverManager.registerDriver(new MyDriver());
}
public MyDriver() {
//
}
}
Gọi Class#forName()
sẽ thực hiện tất cả các khởi tạo tĩnh . Bằng cách này, DriverManager
có thể tìm thấy trình điều khiển được liên kết giữa các trình điều khiển đã đăng ký bằng URL kết nối trong getConnection()
đó đại khái như sau:
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");
}
Nhưng cũng có các trình điều khiển JDBC bị lỗi , bắt đầu với org.gjt.mm.mysql.Driver
ví dụ nổi tiếng, đăng ký không chính xác bên trong Trình xây dựng thay vì một khối tĩnh:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
Cách duy nhất để làm cho nó hoạt động linh hoạt là gọi newInstance()
sau đó! Nếu không, bạn sẽ phải đối mặt với cái nhìn đầu tiên không thể giải thích được "SQLException: không có trình điều khiển phù hợp". Một lần nữa, đây là một lỗi trong trình điều khiển JDBC, không phải trong mã của riêng bạn. Ngày nay, không một trình điều khiển JDBC nào có chứa lỗi này. Vì vậy, bạn có thể (và nên) rời newInstance()
đi.
1: nếu bạn chỉ quan tâm đến khối tĩnh của lớp, việc tải lớp chỉ sẽ làm và sẽ thực thi các khối tĩnh thì tất cả những gì bạn cần là:
Class.forName("Somthing");
2: nếu bạn quan tâm đến việc tải lớp, thực thi các khối tĩnh của nó và cũng muốn truy cập vào phần không tĩnh của nó, thì bạn cần một thể hiện và sau đó bạn cần:
Class.forName("Somthing").newInstance();
"Class.forName ()" trả về Loại lớp cho tên đã cho. "newInstance ()" không trả về một thể hiện của lớp này.
Về kiểu bạn không thể gọi trực tiếp bất kỳ phương thức cá thể nào mà chỉ có thể sử dụng sự phản chiếu cho lớp. Nếu bạn muốn làm việc với một đối tượng của lớp, bạn phải tạo một thể hiện của nó (giống như gọi "new MyClass ()").
Ví dụ cho "Class.forName ()"
Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);
Ví dụ cho "Class.forName (). NewInstance ()"
MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
chỉ cần thêm vào các câu trả lời ở trên, khi chúng ta có một mã tĩnh (tức là khối mã là độc lập) cần phải có trong bộ nhớ, chúng ta có thể trả lại lớp vì vậy chúng ta sẽ sử dụng Class.forname ("someName") nếu chúng ta không có mã tĩnh, chúng ta có thể truy cập Class.forname (). newInstance ("someName") vì nó sẽ tải các khối mã cấp đối tượng (không tĩnh) vào bộ nhớ
Cho dù bạn gọi phương thức Class.forName () bao nhiêu lần, Chỉ khi khối tĩnh được thực thi không nhiều lần:
gói forNameMethodDemo;
lớp công khai 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();
}
}
lớp học công cộng DemoClass {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
đầu ra sẽ là:
in Static block
in Instance block
Đây in Static block
tuyên bố được in một lần duy nhất chứ không phải ba lần.
Class.forName () -> forName () là phương thức tĩnh của lớp Class, nó trả về đối tượng lớp Class được sử dụng để phản ánh không phải đối tượng lớp người dùng, do đó bạn chỉ có thể gọi các phương thức lớp Class trên nó như getMethods (), getConstructor (), v.v.
Nếu bạn quan tâm đến việc chỉ chạy khối tĩnh của lớp (Thời gian chạy đã cho) và chỉ nhận thông tin về các phương thức, hàm tạo, Công cụ sửa đổi, v.v. của lớp bạn có thể thực hiện với đối tượng này mà bạn nhận được bằng Class.forName ()
Nhưng nếu bạn muốn truy cập hoặc gọi phương thức lớp của bạn (lớp mà bạn đã đưa ra trong thời gian chạy) thì bạn cần phải có đối tượng của nó để phương thức mới của lớp Class thực hiện điều đó cho bạn. Nó tạo ra thể hiện mới của lớp và trả lại cho bạn . Bạn chỉ cần gõ nó vào lớp của bạn.
ex-: giả sử Nhân viên là lớp của bạn thì
Lớp a = Class.forName (args [0]);
// args [0] = cmd dòng đối số để cung cấp cho lớp khi chạy.
Nhân viên ob1 = a.newInstance ();
a.newInstance () tương tự như tạo đối tượng bằng Employee () mới.
bây giờ bạn có thể truy cập tất cả các trường và phương thức hiển thị lớp của bạn.