Apa perbedaan antara "Class.forName ()" dan "Class.forName (). NewInstance ()"?

165

Apa perbedaan antara Class.forName()dan Class.forName().newInstance()?

Saya tidak mengerti perbedaan yang signifikan (saya telah membaca sesuatu tentang mereka!). Bisakah bantu saya?

Johanna
sumber

Jawaban:

247

Mungkin contoh yang menunjukkan bagaimana kedua metode digunakan akan membantu Anda untuk memahami hal-hal dengan lebih baik. Jadi, pertimbangkan kelas berikut:

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

Seperti dijelaskan dalam javadoc-nya, panggilan mengembalikan objek yang terkait dengan kelas atau antarmuka dengan nama string yang diberikan yaitu mengembalikan yang dipengaruhi oleh variabel tipe .Class.forName(String) Classtest.Demo.classclazzClass

Kemudian, panggilan menciptakan instance baru dari kelas yang diwakili oleh objek ini . Kelas dipakai sebagai seolah-olah oleh ekspresi dengan daftar argumen kosong. Dengan kata lain, ini di sini sebenarnya setara dengan dan mengembalikan instance baru .clazz.newInstance() Classnewnew Demo()Demo

Dan menjalankan Demokelas ini dengan demikian mencetak output berikut:

Hi!

Perbedaan besar dengan tradisional newadalah yang newInstancememungkinkan untuk instantiate kelas yang Anda tidak tahu sampai runtime, membuat kode Anda lebih dinamis.

Contoh tipikal adalah JDBC API yang memuat, saat runtime, driver yang dibutuhkan untuk melakukan pekerjaan. Wadah EJB, wadah Servlet adalah contoh bagus lainnya: mereka menggunakan pemuatan runtime dinamis untuk memuat dan membuat komponen yang tidak mereka ketahui sebelum runtime.

Sebenarnya, jika Anda ingin melangkah lebih jauh, lihatlah makalah Ted Neward Understanding Class.forName () yang saya kutip dalam paragraf di atas.

EDIT (menjawab pertanyaan dari OP yang diposting sebagai komentar): Kasus driver JDBC agak istimewa. Seperti yang dijelaskan dalam bab DriverManager tentang Memulai dengan JDBC API :

(...) DriverKelas dimuat, dan karenanya secara otomatis terdaftar dengan DriverManager, dalam salah satu dari dua cara:

  1. dengan memanggil metode Class.forName. Ini secara eksplisit memuat kelas driver. Karena tidak tergantung pada pengaturan eksternal apa pun, cara memuat driver ini adalah yang disarankan untuk menggunakan DriverManager kerangka kerja. Kode berikut memuat kelas acme.db.Driver:

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

    Jika acme.db.Drivertelah ditulis sehingga memuatnya menyebabkan instance dibuat dan juga memanggil DriverManager.registerDriverinstance tersebut sebagai parameter (seperti yang seharusnya), maka itu ada dalam DriverManagerdaftar driver dan tersedia untuk membuat koneksi.

  2. (...)

Dalam kedua kasus ini, adalah tanggung jawab kelas yang baru dimuat Driveruntuk mendaftar sendiri dengan menelepon DriverManager.registerDriver. Seperti disebutkan, ini harus dilakukan secara otomatis ketika kelas dimuat.

Untuk mendaftar sendiri selama inisialisasi, driver JDBC biasanya menggunakan blok inisialisasi statis seperti ini:

package acme.db;

public class Driver {

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

    ...
}

Panggilan Class.forName("acme.db.Driver")menyebabkan inisialisasi acme.db.Driverkelas dan dengan demikian eksekusi blok inisialisasi statis. Dan Class.forName("acme.db.Driver")memang akan "membuat" contoh tetapi ini hanya konsekuensi dari bagaimana (baik) Driver JDBC diimplementasikan.

Sebagai catatan, saya akan menyebutkan bahwa semua ini tidak diperlukan lagi dengan JDBC 4.0 (ditambahkan sebagai paket default sejak Java 7) dan fitur auto-loading baru dari driver JDBC 4.0. Lihat peningkatan JDBC 4.0 di Java SE 6 .

Thivent Pascal
sumber
2
di situs di atas tertulis bahwa: "Memanggil Class.forName secara otomatis membuat turunan driver dan mendaftarkannya ke DriverManager, jadi Anda tidak perlu membuat turunan kelas. Jika Anda ingin membuat turunan Anda sendiri , Anda akan membuat duplikat yang tidak perlu, tetapi tidak akan membahayakan. " itu berarti bahwa dengan Class.forName Anda akan membuat instance secara otomatis dan jika Anda ingin membuat yang lain, itu akan membuat instance yang tidak perlu. Jadi, kedua Calss.forName () dan Class.forName (). newInstance () akan membuat instance dari sopir!!
Johanna
10
Driver JDBC adalah "khusus", mereka ditulis dengan blok inisialisasi statis di mana instance dibuat dan diteruskan sebagai parameter DriverManager.registerDriver. Memanggil Class.forNamedriver JDBC menyebabkan inisialisasi dan dengan demikian eksekusi blok statis. Lihat java2s.com/Open-Source/Java-Document/Database-DBMS/… untuk contoh. Jadi ini sebenarnya adalah kasus khusus karena pengemudi internal.
Pascal Thivent
1
Saya perhatikan bahwa dalam jawaban lain , menggunakan Class.newInstance () sangat tidak disarankan. Dianjurkan untuk menggunakan Class.getConstructor (), diikuti oleh Constructor.newInstance () pada gilirannya. Ini menghindari kemungkinan pengecualian.
LS
"newInstance memungkinkan untuk membuat instance kelas yang Anda tidak tahu sampai runtime" dibuat hari saya. Terima kasih.
Code Antusias
37

Class.forName () memberi Anda objek kelas, yang berguna untuk refleksi. Metode yang dimiliki objek ini ditentukan oleh Java, bukan oleh programmer yang menulis kelas. Mereka sama untuk setiap kelas. Memanggil newInstance () pada yang memberikan Anda sebuah instance dari kelas itu (yaitu memanggil Class.forName("ExampleClass").newInstance()itu setara dengan memanggil new ExampleClass()), di mana Anda dapat memanggil metode yang didefinisikan oleh kelas, mengakses bidang yang terlihat dll.

Thomas Lötzer
sumber
29

Di dunia JDBC, praktik normal (menurut JDBC API) adalah yang Anda gunakan Class#forName()untuk memuat driver JDBC. Driver JDBC harus mendaftar di DriverManagerdalam blok statis:

package com.dbvendor.jdbc;

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

public class MyDriver implements Driver {

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

    public MyDriver() {
        //
    }

}

Memohon Class#forName()akan menjalankan semua inisialisasi statis . Dengan cara ini DriverManagerdapat menemukan driver terkait di antara driver terdaftar dengan URL koneksi di getConnection()mana kira-kira terlihat seperti berikut:

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

Tapi ada juga kereta driver JDBC, dimulai dengan org.gjt.mm.mysql.Drivercontoh juga dikenal, yang tidak benar mendaftarkan diri dalam Constructor bukan blok statis:

package com.dbvendor.jdbc;

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

public class BadDriver implements Driver {

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

}

Satu-satunya cara untuk membuatnya bekerja secara dinamis adalah menelepon newInstance()sesudahnya! Kalau tidak, Anda akan menghadapi pandangan pertama yang tidak dapat dijelaskan "SQLException: no driver yang sesuai". Sekali lagi, ini adalah bug pada driver JDBC, bukan di kode Anda sendiri. Saat ini, tidak ada driver JDBC yang boleh mengandung bug ini. Jadi Anda dapat (dan harus) meninggalkan tempat newInstance()itu.

BalusC
sumber
17

1: jika Anda hanya tertarik pada blok statis kelas, pemuatan kelas hanya akan dilakukan, dan akan menjalankan blok statis maka yang Anda butuhkan adalah:

Class.forName("Somthing");

2: jika Anda tertarik untuk memuat kelas, jalankan blok-blok statisnya dan juga ingin mengakses bagian non-statisnya, maka Anda memerlukan sebuah instance dan kemudian Anda perlu:

Class.forName("Somthing").newInstance();
Hussain Akhtar Wahid 'Ghouri'
sumber
Jawaban yang sangat bagus! Jelas dan ringkas!
gaurav
6

Class.forName () mendapatkan referensi ke Class, Class.forName (). NewInstance () mencoba menggunakan konstruktor no-arg untuk Kelas untuk mengembalikan instance baru.

Gopi
sumber
3

"Class.forName ()" mengembalikan Tipe-Kelas untuk nama yang diberikan. "newInstance ()" mengembalikan instance kelas ini.

Pada tipe yang Anda tidak dapat memanggil langsung metode instance tetapi hanya dapat menggunakan refleksi untuk kelas. Jika Anda ingin bekerja dengan objek kelas Anda harus membuat turunannya (sama dengan memanggil "MyClass baru ()").

Contoh untuk "Class.forName ()"

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

Contoh untuk "Class.forName (). NewInstance ()"

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

hanya menambahkan jawaban di atas, ketika kita memiliki kode statis (mis. blok kode adalah contoh independen) yang perlu ada dalam memori, kita dapat meminta kelas dikembalikan sehingga kita akan menggunakan Class.forname ("someName") yang lain jika kita jangan punya kode statis, kita bisa menggunakan Class.forname (). newInstance ("someName") karena akan memuat blok kode level objek (non statis) ke memori

sij
sumber
1

Tidak peduli berapa kali Anda memanggil metode Class.forName (), Hanya sekali blok statis dijalankan tidak beberapa kali:

paket untukNameMethodDemo;

MainClass kelas publik {

    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 kelas publik {

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

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

}

output akan menjadi:

in Static block in Instance block

Ini in Static blockPernyataan dicetak hanya sekali bukan tiga kali.

Priyanka Wagh
sumber
0

Class.forName () -> forName () adalah metode statis kelas Kelas yang dikembalikannya objek kelas Kelas yang digunakan untuk refleksi bukan objek kelas pengguna sehingga Anda hanya dapat memanggil metode kelas Kelas di atasnya seperti getMethods (), getConstructors () dll.

Jika Anda peduli hanya menjalankan blok statis dari kelas Anda (diberikan Runtime) dan hanya mendapatkan informasi tentang metode, konstruktor, Modifier dll dari kelas Anda, Anda dapat melakukannya dengan objek ini yang Anda dapatkan menggunakan Class.forName ()

Tetapi jika Anda ingin mengakses atau memanggil metode kelas Anda (kelas yang telah Anda berikan saat runtime) maka Anda perlu memiliki objeknya sehingga metode Kelas baru melakukannya untuk Anda. Ini membuat instance baru dari kelas dan mengembalikannya kepada Anda Anda hanya perlu mengetikkan gips ke kelas Anda.

mis.: anggaplah Karyawan adalah kelas Anda saat itu

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

// args [0] = argumen garis cmd untuk memberikan kelas saat runtime.

Karyawan ob1 = a.newInstance ();

a.newInstance () mirip dengan membuat objek menggunakan Karyawan baru ().

sekarang Anda dapat mengakses semua bidang dan metode yang terlihat kelas Anda.

Vinod Malkani
sumber