۵ راه مختلف برای ساختن اشیا در جاوا
توسعهدهندگان جاوا معمولا هر روز تعداد زیادی شئ میسازند. شاید ما همیشه از سیستمهای مدیریت وابستگی مثل Spring استفاده میکنیم تا این اشیا را بسازیم. اما راههای زیادی برای ساخت اشیا وجود دارند که در این مطلب به آنها اشاره میکنیم.
۵ راه کلی برای ساخت اشیا در جاوا وجود دارد که با مثال توضیح میدهیم:
constructor فراخوانی میشود | استفاده از کلمه کلیدی new |
constructor فراخوانی میشود | استفاده از تابع newInstance از کلاس Class |
constructor فراخوانی میشود | استفاده از تابع newInstance از کلاس Constructor |
بدون فراخوانی constructor | استفاده از تابع clone |
بدون فراخوانی constructor | استفاده از deserialization |
اگر که برنامهای که در پایان داده شده است را بررسی کنید، خواهید دید که توابع ۱،۲،۳ از constructor برای ساختن اشیا استفاده میکنند در حالیکه ۴،۵ بدون constructor اشیا را میسازند.
۱. استفاده از کلمه کلیدی new:
رایجترین و معمولترین راه برای ساختن اشیا و سادهترین آنهاست. با استفاده از این روش میتوانیم هر constructorای که میخواهیم را صدا بزنیم (بدون آرگومان یا با پارامتر)
Employee emp1 = new Employee();
0: new #19 // class org/programming/mitra/exercises/Employee 3: dup 4: invokespecial #21 // Method org/programming/mitra/exercises/Employee."":()V
۲. استفاده از تابع newInstance از کلاس Class
این متد constructor بدون آرگومان را فراخوانی میکند تا اشیا را بسازد.
ما میتوانیم یک شی را با newInstance به این شکل بسازیم:
Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee").newInstance();
یا
Employee emp2 = Employee.class.newInstance();
51: invokevirtual #70 // Method java/lang/Class.newInstance:()Ljava/lang/Object;
۳. استفاده از تابع newInstance از کلاس Constructor
مشابه تابع newInstance از کلاس Class، یک تابع newInstance در کلاس java.lang.reflect.Constructor وجود دارد که میتوانیم برای ساخت اشیا از آن استفاده کنیم. به علاوه میتوانیم یک constructor با پارامتر و یک private constructor هم با این روش فراخوانی کنیم.
Constructor<Employee> constructor = Employee.class.getConstructor(); Employee emp3 = constructor.newInstance();
111: invokevirtual #80 // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;
هر دوی این توابع newInstance به عنوان راههای بازتابی برای ساخت اشیا شناخته میشوند. در حقیقت این متد در کلاس Class از همین متد در کلاس Constructor استفاده میکند. به همین دلیل دومی ترجیح داده میشود و در اغلب چارچوبها مثل Spring، Hibernate، Struts و … مورد استفاده قرار میگیرد. برای اینکه تفاوت بین این دو متد را بهتر متوجه شوید این مطلب را بخوانید.
۴. از تابع clone استفاده کنید.
هروقت تابع clone را روی هر شئی صدا میزنیم، JVM دقیقا یک شی برای ما میسازد و تمام محتویات شئ قبلی را در آن کپی میکند. با این راه هیچ constructorای صدا نمیشود.
برای استفاده از متد clone روی شئ نیاز داریم اینترفیس Clonable را پیاده سازی کرده و متد clone را در آن تعریف کنیم:
Employee emp4 = (Employee) emp3.clone();
162: invokevirtual #87 // Method org/programming/mitra/exercises/Employee.clone ()Ljava/lang/Object;
۵. استفاده از deserialization
هر زمانی که شئی را serialize و deserialize میکنیم، JVM یک شي جدا برای ما میسازد. در deserialization، JVM از هیچ constuctorای برای ساخت اشیا استفاده نمیکند.
برای deserialize کردن یک شئ لازم است اینترفیس Serializable را در کلاسمان پیادهسازی کنیم:
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj")); Employee emp5 = (Employee) in.readObject();
261: invokevirtual #118 // Method java/io/ObjectInputStream.readObject:()Ljava/lang/Object;
همانطور که در بایت کد بالا دیده میشود، همه چهار متد صدا زده شده و به invokevirtual که ساخت شئ مستقیم توسط این متدها مدیریت میشود تبدیل شده است. به جز در مورد اول که به دو فراخوانی تبدیل شده است. یکی از آنها new و دیگری invokespecial است.
مثال:
کلاس کارمند را درنظر بگیرید:
class Employee implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String name; public Employee() { System.out.println("Employee Constructor Called..."); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "Employee [name=" + name + "]"; } @Override public Object clone() { Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } }
در برنامهجاوا زیر میخواهیم به پنج راه مختلف از این کلاس نمونه بسازیم. کد آن در گیت هاب هم در دسترس است:
ublic class ObjectCreation { public static void main(String... args) throws Exception { // By using new keyword Employee emp1 = new Employee(); emp1.setName("Naresh"); System.out.println(emp1 + ", hashcode : " + emp1.hashCode()); // By using Class class's newInstance() method Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee") .newInstance(); // Or we can simply do this // Employee emp2 = Employee.class.newInstance(); emp2.setName("Rishi"); System.out.println(emp2 + ", hashcode : " + emp2.hashCode()); // By using Constructor class's newInstance() method Constructor<Employee> constructor = Employee.class.getConstructor(); Employee emp3 = constructor.newInstance(); emp3.setName("Yogesh"); System.out.println(emp3 + ", hashcode : " + emp3.hashCode()); // By using clone() method Employee emp4 = (Employee) emp3.clone(); emp4.setName("Atul"); System.out.println(emp4 + ", hashcode : " + emp4.hashCode()); // By using Deserialization // Serialization ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj")); out.writeObject(emp4); out.close(); //Deserialization ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj")); Employee emp5 = (Employee) in.readObject(); in.close(); emp5.setName("Akash"); System.out.println(emp5 + ", hashcode : " + emp5.hashCode()); } }
این برنامه خروجی زیر را دارد:
Employee Constructor Called... Employee [name=Naresh], hashcode : -1968815046 Employee Constructor Called... Employee [name=Rishi], hashcode : 78970652 Employee Constructor Called... Employee [name=Yogesh], hashcode : -1641292792 Employee [name=Atul], hashcode : 2051657 Employee [name=Akash], hashcode : 63313419
منبع: