Odpowiedzi:
Może przykład pokazujący, jak używane są obie metody, pomoże ci lepiej zrozumieć. Rozważmy więc następującą klasę:
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();
}
}
Jak wyjaśniono w jego javadoc, wywołanie zwraca obiekt skojarzony z klasą lub interfejsem o podanej nazwie łańcucha, tj. Zwraca zmienną typu, na którą ma to wpływ .Class.forName(String)
Class
test.Demo.class
clazz
Class
Następnie wywołanie tworzy nowe wystąpienie klasy reprezentowanej przez ten obiekt. Klasa jest tworzona tak, jakby była wyrażeniem z pustą listą argumentów. Innymi słowy, jest to w rzeczywistości równoważne a i zwraca nowe wystąpienie .clazz.newInstance()
Class
new
new Demo()
Demo
Uruchomienie tej Demo
klasy powoduje wypisanie następującego wyniku:
Hi!
Duża różnica w stosunku do tradycyjnej new
polega na tym, że newInstance
umożliwia utworzenie instancji klasy, której nie znasz do czasu uruchomienia, dzięki czemu kod jest bardziej dynamiczny.
Typowym przykładem jest interfejs API JDBC, który ładuje w czasie wykonywania dokładny sterownik wymagany do wykonania pracy. Kontenery EJB, kontenery serwletów to inne dobre przykłady: używają dynamicznego ładowania środowiska uruchomieniowego do ładowania i tworzenia komponentów, o których nic nie wiedzą przed uruchomieniem.
Właściwie, jeśli chcesz pójść dalej, spójrz na artykuł Teda Newarda Understanding Class.forName (), który parafrazowałem w akapicie powyżej.
EDYCJA (odpowiadanie na pytanie z PO zamieszczone jako komentarz): Przypadek sterowników JDBC jest nieco wyjątkowy. Jak wyjaśniono w rozdziale DriverManager w podręczniku Pierwsze kroki z interfejsem API JDBC :
(...)
Driver
Klasa jest ładowana, a zatem automatycznie rejestrowana w programieDriverManager
, na jeden z dwóch sposobów:
wywołując metodę
Class.forName
. To jawnie ładuje klasę sterownika. Ponieważ nie zależy to od żadnej zewnętrznej konfiguracji, ten sposób ładowania sterownika jest zalecany do korzystania zDriverManager
frameworka. Poniższy kod ładuje klasęacme.db.Driver
:Class.forName("acme.db.Driver");
Jeśli
acme.db.Driver
został napisany w taki sposób, że jego załadowanie powoduje utworzenie instancji, a także wywołanieDriverManager.registerDriver
z tą instancją jako parametrem (tak jak powinno), to znajduje się naDriverManager
liście sterowników i jest dostępne do utworzenia połączenia.(...)
W obu tych przypadkach to nowo załadowana
Driver
klasa musi zarejestrować się przez wywołanieDriverManager.registerDriver
. Jak wspomniano, powinno to być zrobione automatycznie po załadowaniu klasy.
Aby zarejestrować się podczas inicjalizacji, sterownik JDBC zazwyczaj używa statycznego bloku inicjalizacyjnego w następujący sposób:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
Wywołanie Class.forName("acme.db.Driver")
powoduje inicjalizację acme.db.Driver
klasy, a tym samym wykonanie statycznego bloku inicjalizacyjnego. I Class.forName("acme.db.Driver")
rzeczywiście „utworzy” instancję, ale jest to tylko konsekwencja tego, jak (dobry) sterownik JDBC został zaimplementowany.
Na marginesie wspomnę, że wszystko to nie jest już wymagane w JDBC 4.0 (dodanym jako domyślny pakiet od wersji Java 7) i nowej funkcji automatycznego ładowania sterowników JDBC 4.0. Zobacz ulepszenia JDBC 4.0 w Java SE 6 .
DriverManager.registerDriver
. Wywołanie Class.forName
sterownika JDBC powoduje jego inicjalizację, a tym samym wykonanie bloku statycznego. Na przykład spójrz na java2s.com/Open-Source/Java-Document/Database-DBMS/… . Jest to więc właściwie szczególny przypadek ze względu na elementy wewnętrzne sterownika.
Class.forName () podaje obiekt klasy, który jest przydatny do refleksji. Metody, które ma ten obiekt, są definiowane przez Javę, a nie przez programistę piszącego klasę. Są takie same dla każdej klasy. Wywołanie newInstance () on daje instancję tej klasy (tj. Wywołanie Class.forName("ExampleClass").newInstance()
jej jest równoważne wywołaniu new ExampleClass()
), na której można wywołać metody zdefiniowane przez klasę, uzyskać dostęp do widocznych pól itp.
W świecie JDBC normalną praktyką (zgodnie z interfejsem API JDBC) jest Class#forName()
ładowanie sterownika JDBC. Sterownik JDBC powinien mianowicie zarejestrować się w DriverManager
statycznym bloku:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class MyDriver implements Driver {
static {
DriverManager.registerDriver(new MyDriver());
}
public MyDriver() {
//
}
}
Wywołanie Class#forName()
spowoduje wykonanie wszystkich statycznych inicjatorów . W ten sposób DriverManager
może znaleźć powiązany sterownik wśród zarejestrowanych sterowników według adresu URL połączenia, podczas getConnection()
którego z grubsza wygląda to następująco:
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");
}
Ale były też buggy sterowników JDBC, zaczynając org.gjt.mm.mysql.Driver
jako dobrze znany przykład, który niepoprawnie rejestruje się wewnątrz konstruktora zamiast statycznego bloku:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
Jedynym sposobem, aby działał dynamicznie, jest newInstance()
późniejsze zadzwonienie ! W przeciwnym razie napotkasz na pierwszy rzut oka niewytłumaczalne „SQLException: brak odpowiedniego sterownika”. Po raz kolejny jest to błąd w sterowniku JDBC, a nie w Twoim własnym kodzie. Obecnie żaden sterownik JDBC nie powinien zawierać tego błędu. Więc możesz (i powinieneś) zostawić to newInstance()
daleko.
1: jeśli jesteś zainteresowany tylko statycznym blokiem klasy, ładowanie samej klasy wystarczyłoby i wykonałoby statyczne bloki, wszystko czego potrzebujesz to:
Class.forName("Somthing");
2: jeśli jesteś zainteresowany ładowaniem klasy, wykonywaniem jej bloków statycznych, a także chcesz uzyskać dostęp do jej części niestatycznej, potrzebujesz instancji, a następnie potrzebujesz:
Class.forName("Somthing").newInstance();
„Class.forName ()” zwraca typ klasy dla podanej nazwy. „newInstance ()” zwraca instancję tej klasy.
W typie nie można bezpośrednio wywoływać żadnych metod instancji, ale można używać tylko odbicia dla klasy. Jeśli chcesz pracować z obiektem klasy, musisz utworzyć jego instancję (tak samo jak wywołanie „new MyClass ()”).
Przykład dla „Class.forName ()”
Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);
Przykład dla „Class.forName (). NewInstance ()”
MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
po prostu dodając do powyższych odpowiedzi, gdy mamy kod statyczny (tj. blok kodu jest niezależny od instancji), który musi być obecny w pamięci, możemy zwrócić klasę, więc użyjemy Class.forname ("someName") w przeciwnym razie, jeśli będziemy nie mamy kodu statycznego, możemy przejść do Class.forname (). newInstance ("someName"), ponieważ załaduje do pamięci bloki kodu na poziomie obiektu (nie statyczne)
Bez względu na to, ile razy wywołasz metodę Class.forName (), tylko wtedy, gdy blok statyczny zostanie wykonany nie wielokrotnie:
pakiet forNameMethodDemo;
public class 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();
}
}
klasa publiczna DemoClass {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
wynik będzie:
in Static block
in Instance block
To in Static block
oświadczenie jest drukowane tylko raz, a nie trzy razy.
Class.forName () -> forName () to statyczna metoda klasy Class, która zwraca obiekt klasy Class używany do odbicia, a nie obiekt klasy użytkownika, więc możesz wywołać na nim tylko metody klasy Class, takie jak getMethods (), getConstructors () itp.
Jeśli zależy Ci na uruchamianiu tylko statycznego bloku swojej (podanej w Runtime) klasie i pobieraniu tylko informacji o metodach, konstruktorach, modyfikatorze itp. Swojej klasy, możesz zrobić z tym obiektem, który otrzymujesz za pomocą Class.forName ()
Ale jeśli chcesz uzyskać dostęp lub wywołać swoją metodę klasy (klasę, którą podałeś w czasie wykonywania), musisz mieć jej obiekt, więc newInstance metoda klasy Class zrobi to za Ciebie. Utworzy nową instancję klasy i zwróci ci ją Wystarczy, że prześlesz to na swoją klasę.
ex-: przypuśćmy, że pracownik jest wtedy twoją klasą
Class a = Class.forName (args [0]);
// args [0] = argument linii cmd do nadania klasie w czasie wykonywania.
Pracownik ob1 = a.newInstance ();
a.newInstance () jest podobne do tworzenia obiektu przy użyciu funkcji new Employee ().
teraz możesz uzyskać dostęp do wszystkich widocznych pól i metod swojej klasy.