Java创建对象的五种方式:
(1)使用new关键字
(2)使用Object类的clone方法
(3)使用Class类的newInstance方法
(4)使用Constructor类中的newInstance方法
(5)使用序列化和反序列化
(1)使用new关键字创建对象:
使用new关键字是我们入门最常见的一种创建对象的一种方式,使用new关键字创建对象的核心是对象的声明和对象分配内存。
①对象的声明:类的名字 对象名字;例如 People Zhangsan;
People为类的名字,而zhangsan则是对象名字。
②对象分配内存:使用new关键字和构造方法为声明的对象进行内存分配。
People Zhangsan; //声明对象
Zhangsan = new People(); //对象分配内存
③对象的内存模型:
(1)People Zhangsan; //声明对象
声明对象声明对象后,此时对象是一个空对象,空对象是不能使用的,因为必须对对象进行内存分配后才可以使用这个对象,即我们常说的我们要为对象分配实体。
(2)Zhangsan = new People(); //对象分配内存
① 为对象分配内存,则是指开始对People类中的成员变量分配内存空间,然后执行构造方法中的语句。
注意:当成员变量在声明时如果没有指定初始数值,所使用的构造方法也没有对成员变量进行初始化操作,那么整形变量的默认初始值为0,浮点型默认变量为0.0,对于Boolean类型变量的默认数值为false,对于引用类型,则初始数值为null。
②当分配完内存后,则返回一个引用变量Zhangsan,相当于一个号码,用于标明我们创建的内存属于Zhangsan这个实体的,也用来确保刚刚创建的这些变量将由Zhangsan来进行管理。
③并且需要注意一个类可以通过new关键字创建多个不同的对象,但是这些对象也会被分配到不同的内存空间,这就是等价于改变其中一个对象的状态不会影响其他对象的状态。
(2)使用Class类的newInstance()创建对象(核心思想利用反射的思想)
(1)什么叫做反射机制呢?我查了一下百度,个人理解看来反射相当能够检测类本身的属性、方法的一种能力。
package com.day20230217;
public class People {
String userName;
Integer age;
boolean isWedding;
int number;
People(){
System.out.println("我是默认构造方法");
}
}
package com.day20230217;
public class ClassNewInstance {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
System.out.println("利用class中的newInstance()方法创建对象");
People people = People.class.newInstance();
System.out.println(people);
people.age = 10;
people.userName = "张三";
System.out.println(people);
}
}
①首先要注意使用Class.newInstance()方法要保证类中必须包含默认构造方法,如果对构造方法进行改动将会报错。
②注意区别Class.newInstance()创建对象和使用new关键字创建对象的区别:
https://blog.csdn.net/qq_39800695/article/details/104940040
(3)使用Constructor类中的newInstance方法
package com.day20230217;
/**
* @author 袁明兴
*/
public class People {
String userName;
Integer age;
boolean isWedding;
int number;
public People(){
System.out.println("我是默认的构造方法进行修改");
}
}
System.out.println("使用Constructor类中的newInstance方法");
Constructor<People> constructor = People.class.getConstructor();
People people = constructor.newInstance();
System.out.println(people);
people.userName = "张三";
people.setAge(17);
System.out.println(people);
需要注意使用Constructor类中的getConstructor()方法去获取构造器时,必须保证此时类中的构造方法的访问权限表示符为public,如果构造方法的访问权限符不是public的那么可以考虑使用getDeclaredConstructor()方法,参考下图:
补充:
①private是最小的访问权限控制符,其修饰的成员变量、构造方法和普通方法只能在定义它们的类中被操作或使用。
②默认修饰比private要大,它修饰的成员变量、构造方法和普通方法不仅可以在其定义类中使用,还可以在与定义类同包的其它类中调用,继承与非继承均可。
③protected的使用范围比友好的还要大一点,它修饰的成员变量、构造方法和普通方法不仅可以在同包中使用,还可以在不同包中使用,但前提是只能在定义类的子类中使用。
④public是访问权限修饰符中最大的,无论是否是一个包内的,无论是否是继承关系,只要是一个工程里的,就可以调用。
(4)序列化和反序列化创建对象:
什么叫做序列化呢?
简单来说将对象当前的状态信息转换成可存储或者是可运输的形式的过程,我们称之为序列化,相似反序列化则是其相反含义!!
package com.leetch;
import java.io.*;
class Student implements Serializable{
private static final long serialVersionUID=1L;
private String nameString ;
private int ageInt;
public String getname(){
return this.nameString;
}
public int getage(){
return this.ageInt;
}
public void setName(String name){
this.nameString = name;
}
public void setAge(int age){
this.ageInt=age;
}
}
public class SerialTest {
public static void main(String[] args){
Student student = new Student(); //创建一个学生对象
student.setAge(20);
student.setName("Yifan");
try {
ObjectOutputStream ooStream=new ObjectOutputStream(
new FileOutputStream("F:/文件/my Documents/Coder/JAVA/File/obj.txt"));
//创建一个对象输出流
ooStream.writeObject(student); //把对象写入输出流,序列化,又称串化,把java对象内存中的数据采编成一串二进制的数据,然后把这些数据
//存放在可以持久的数据存储设备,如磁盘等
ooStream.close(); //关闭输出流
//创建一个对象输入流
ObjectInputStream oisStream= new ObjectInputStream(
new FileInputStream("F:/文件/my Documents/Coder/JAVA/File/obj.txt"));
Object object = oisStream.readObject(); //读出已经序列化的对象
Student stubac = (Student)object; //进行类型转换
//打印数据到控制台,检查序列化和反序列化是否成功?
System.out.println("student name is"+stubac.getname());
System.out.println("student age is"+stubac.getage());
oisStream.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
(5)通过clone(克隆)的方式来创建对象
clone方法来源于java中object类,在jdk中的解释为:该方法返回一个此对象的副本。复制对象就是在内存中分配一个和原一模一样的空间,在此创建新的对象。
在这里我们要注意浅拷贝与深拷贝的概念:
给大家一个链接:
https://blog.csdn.net/u014282578/article/details/127782511
利用克隆方式进行创建对象的步骤:
①首先我们需要在需要clone的类中实现Cloneable接口,否则会出现java.lang.CloneNotSupportedException异常。
②由于Object类中clone方法是protected 修饰的,所以我们必须在需要克隆的类中重写克隆方法。
(我们知道所有定义的类都是Object类的子类,protected的使用范围比友好的还要大一点,它修饰的成员变量、构造方法和普通方法不仅可以在同包中使用,还可以在不同包中使用,但前提是只能在定义类的子类中使用。)
③调用clone()方法开始进行对象的克隆
package com.day20230217;
public class People implements Cloneable {
String userName;
Integer age;
boolean isWedding;
int number;
public People() {
System.out.println("我是默认的构造方法进行修改");
}
@Override
public String toString() {
return "People{" +
"userName='" + userName + '\'' +
", age=" + age +
", isWedding=" + isWedding +
", number=" + number +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
People people1 = new People();
People people2 =(People) people1.clone();
people1.userName = "张三";
people2.userName = "李四";
System.out.println(people1);
System.out.println(people2);
System.out.println(people1 == people2);
大家再细看一下这段程序代码和上面的程序代码之间的区别: