前几天与同事谈过此事。
有明显的使用构造函数,但其他方法是什么?
在java中创建对象有四种不同的方法:
A.使用new关键字
这是在java中创建对象的最常用方法。几乎99%的对象都是以这种方式创建的。
1
| MyObject object = new MyObject(); |
B.使用Class.forName()
如果我们知道类的名称并且它是否有公共默认构造函数,我们可以用这种方式创建一个对象。
1
| MyObject object = (MyObject) Class.forName("subin.rnd.MyObject").newInstance(); |
C.使用clone()
clone()可用于创建现有对象的副本。
1 2
| MyObject anotherObject = new MyObject();
MyObject object = (MyObject) anotherObject.clone(); |
D.使用object deserialization
对象反序列化只不过是从序列化形式创建对象。
1 2
| ObjectInputStream inStream = new ObjectInputStream(anInputStream );
MyObject object = (MyObject) inStream.readObject(); |
你可以从这里阅读它们。
有各种方法:
-
通过Class.newInstance。
-
通过Constructor.newInstance。
-
通过反序列化(使用最派生的非可序列化基类的no-args构造函数)。
-
通过Object.clone(不调用构造函数)。
-
通过JNI(应该调用构造函数)。
-
通过任何其他方法为您调用new。
-
我猜你可以将类加载描述为创建新对象(例如interned String)。
-
作为声明中初始化的一部分的文字数组(没有数组的构造函数)。
-
"varargs"(...)方法调用中的数组(没有数组的构造函数)。
-
非编译时间常量字符串连接(在典型的实现中恰好产生至少四个对象)。
-
导致运行时创建和抛出异常。例如throw null;或"".toCharArray()[0]。
-
当然,哦,原始拳击(除非缓存)。
-
JDK8应该有lambda(基本上是简洁的匿名内部类),它们被隐式转换为对象。
-
为了完整性(和Pa?lo Ebermann),还有一些new关键字的语法。
在Java语言中,创建对象的唯一方法是通过调用其构造函数,无论是显式还是隐式。使用反射导致对构造函数方法的调用,反序列化使用反射来调用构造函数,工厂方法将调用包装到构造函数以抽象实际构造,而克隆同样是包装构造函数调用。
是的,您可以使用反射创建对象。例如,String.class.newInstance()将为您提供一个新的空String对象。
在Java中创建对象有五种不同的方法,
1.使用new关键字→构造函数进行调用
1
| Employee emp1 = new Employee(); |
2.使用Class的newInstance()方法→构造函数调用
1 2
| Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee")
.newInstance(); |
它也可以写成
1
| Employee emp2 = Employee.class.newInstance(); |
3.使用Constructor的newInstance()方法→构造函数调用
1 2
| Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance(); |
4.使用clone()方法→无构造函数调用
1
| Employee emp4 = (Employee) emp3.clone(); |
5.使用反序列化→没有构造函数调用
1 2
| ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject(); |
前三个方法new关键字和newInstance()都包含构造函数调用,但后来两个克隆和反序列化方法创建对象而不调用构造函数。
所有上述方法都具有与它们相关联的不同字节码,阅读用Java创建对象的不同方式,以示例和更详细的描述,例如,所有这些方法的字节码转换。
然而,人们可以争辩说创建数组或字符串对象也是创建对象的一种方式,但这些事情仅对某些类更具体,并由JVM直接处理,而我们可以使用这5种方式创建任何类的对象。
克隆和反序列化。
此外,您可以将数据反序列化为对象。这不是通过类构造函数!
更新:感谢汤姆在你的评论中指出这一点!迈克尔也进行了实验。
It goes through the constructor of the most derived non-serializable superclass.
And when that class has no no-args constructor, a InvalidClassException is thrown upon de-serialization.
请参阅汤姆的回答,以便对所有病例进行全面治疗;-)
有没有其他方法创建一个对象而不在java中使用"new"关键字
你也可以使用
1
| Object myObj = Class.forName("your.cClass").newInstance(); |
如果您是java新手,应该注意这一点,每个对象都继承自Object
protected native clone clone()抛出CloneNotSupportedException;
有一种对象,它不能由普通的实例创建机制(调用构造函数)构造:数组。数组是用。创建的
1
| A[] array = new A[len]; |
要么
1
| A[] array = new A[] { value0, value1, value2 }; |
正如Sean在评论中所说,这在语法上类似于构造函数调用,并且在内部它只是分配和零初始化(或使用显式内容初始化,在第二种情况下)一个内存块,带有一些标头来指示类型和长度。
将参数传递给varargs-method时,也会隐式创建(并填充)数组。
第四种方式
1
| A[] array = (A[]) Array.newInstance(A.class, len); |
当然,克隆和反序列化也适用于此。
标准API中有许多方法可以创建数组,但实际上它们都使用这些方法中的一种(或多种)。
其他方式,如果我们是详尽无遗的。
-
在Oracle JVM上是Unsafe.allocateInstance(),它在不调用构造函数的情况下创建实例。
-
使用字节代码操作,您可以将代码添加到anewarray,multianewarray,newarray或new。可以使用诸如ASM或BCEL之类的库来添加这些。 Oracle的Java附带了一个版本的bcel。同样,这不会调用构造函数,但您可以将构造函数称为单独调用。
-
使用new运算符(从而调用构造函数)
-
使用反射clazz.newInstance()(再次调用构造函数)。或者通过clazz.getConstructor(..).newInstance(..)(再次使用构造函数,但您可以选择哪一个)
通过调用对象类的构造函数来总结答案 - 一种主要方式。
更新:另一个答案列出了两种不涉及使用构造函数的方法 - 解除分类和克隆。
反思也将为你完成这项工作。
1
| SomeClass anObj = SomeClass.class.newInstance(); |
是另一种创建类的新实例的方法。在这种情况下,您还需要处理可能抛出的异常。
反射:
1
| someClass.newInstance(); |
在Java中创建对象有五种不同的方法:
1.使用`new`关键字:
这是在Java中创建对象的最常用方法。几乎99%的对象都是以这种方式创建的。
1
| MyObject object = new MyObject();//normal way |
2.使用工厂方法:
1
| ClassName ObgRef=ClassName.FactoryMethod(); |
例:
1
| RunTime rt=Runtime.getRunTime();//Static Factory Method |
3.使用克隆概念:
通过使用clone(),clone()可用于创建现有对象的副本。
1 2
| MyObjectName anotherObject = new MyObjectName();
MyObjectName object = anotherObjectName.clone();//cloning Object |
4.使用`Class.forName()`:
如果我们知道类的名称并且它是否有公共默认构造函数,我们可以用这种方式创建一个对象。
1
| MyObjectName object = (MyObjectNmae) Class.forName("PackageName.ClassName").newInstance(); |
例:
1
| String st=(String)Class.forName("java.lang.String").newInstance(); |
5.使用对象反序列化:
对象反序列化只不过是从序列化形式创建对象。
1 2
| ObjectInputStreamName inStream = new ObjectInputStreamName(anInputStream );
MyObjectName object = (MyObjectNmae) inStream.readObject(); |
您还可以克隆现有对象(如果它实现Cloneable)。
1
| Foo fooClone = fooOriginal.clone (); |
方法1
使用新关键字。这是在java中创建对象的最常用方法。几乎99%的对象都是以这种方式创建的。
1
| Employee object = new Employee(); |
方法2
使用Class.forName()。 Class.forName()为您提供了类对象,它对于反射非常有用。此对象具有的方法由Java定义,而不是由编写类的程序员定义。每个班级都是一样的。调用newInstance()会给你一个该类的实例(即callingClass.forName("ExampleClass")。newInstance()它相当于调用new ExampleClass()),你可以在其上调用类定义的方法,访问可见字段等。
1
| Employee object2 = (Employee) Class.forName(NewEmployee).newInstance(); |
Class.forName()将始终使用调用者的ClassLoader,而ClassLoader.loadClass()可以指定不同的ClassLoader。我相信Class.forName也会初始化加载的类,而ClassLoader.loadClass()方法不会立即执行此操作(直到第一次使用它才会初始化)。
另一个必读:
Java:线程状态简介与示例
简单的Java Enum示例
方法3
使用clone()。 clone()可用于创建现有对象的副本。
1 2
| Employee secondObject = new Employee();
Employee object3 = (Employee) secondObject.clone(); |
方法4
使用newInstance()方法
1
| Object object4 = Employee.class.getClassLoader().loadClass(NewEmployee).newInstance(); |
方法5
使用对象反序列化。对象反序列化只不过是从序列化形式创建对象。
1 2 3 4 5 6 7 8 9 10 11 12
| // Create Object5
// create a new file with an ObjectOutputStream
FileOutputStream out = new FileOutputStream("");
ObjectOutputStream oout = new ObjectOutputStream(out);
// write something in the file
oout.writeObject(object3);
oout.flush();
// create an ObjectInputStream for the file we created before
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("crunchify.txt"));
Employee object5 = (Employee) ois.readObject(); |
从API用户的角度来看,构造函数的另一种替代方法是静态工厂方法(如BigInteger.valueOf()),但对于API作者(技术上"真实"),仍然使用构造函数创建对象。
取决于你的意思,但其他一些是:
-
克隆方法
-
反序列化
-
反思(Class.newInstance())
-
反射(构造函数对象)
还有ClassLoader.loadClass(s??tring),但这并不经常使用。
如果你想成为一名律师,那么由于数组的.length属性,数组在技术上是对象。所以初始化一个数组会创建一个对象。
我们可以用5种方式创建对象:
由新运营商
通过反射(例如Class.forName()后跟Class.newInstance())
按工厂方法
通过克隆
通过反射api
我们也可以这种方式创建对象: -
没人讨论过。