Java类初始化和实例化
Java有以下几种方式创建类对象:
- 利用new关键字
- 利用反射Class.newInstance
- 利用Constructor.newIntance(相比Class.newInstance多了有参和私有构造函数)
- 利用Cloneable/Object.clone()
- 利用反序列化
Constructor.newInstance不支持带原型入参的构造函数。
调用Class.getConstructor()方法获取无参默认构造Constructor时,如果用户自定义了有参构造函数,因为此时java并不会生成默认构造函数,所以Class.getConstructor()方法因找不到无参默认构造函数而抛异常。此时需要显示定义默认构造函数:
// Initialization.java
public class Initialization {
private int age = 2000;
private int salary = age + 1000;
private String name = "Tom";
public Initialization() {
print();
}
public Initialization(Integer salary, String name) {
print();
this.salary = salary;
this.name = name;
print();
}
/**
* Static code
*/
{
salary += 500;
}
private void print() {
System.out.println("age=" + this.age);
System.out.println("salary=" + this.salary);
System.out.println("name=" + this.name);
}
public static Initialization construct(int salary, String name) throws Exception {
Constructor<Initialization> constructorWithNoParams = Initialization.class.getConstructor();
Constructor<Initialization> constructorWithParams = Initialization.class.getConstructor(Integer.class, String.class);
return salary <= 0 || name == null ? constructorWithNoParams.newInstance() : constructorWithParams.newInstance(salary, name);
}
public Initialization deSerialize() throws Exception {
// 写对象
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.txt"));
output.writeObject(this);
output.close();
// 读取对象
ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.txt"));
return (Initialization) input.readObject();
}
}
再来看下Initialization类被编译为.class文件后的信息:
public class Initialization {
private int age = 2000;
private int salary;
private String name;
public Initialization() {
this.salary = this.age + 1000;
this.name = "Tom";
this.salary += 500;
this.print();
}
public Initialization(Integer salary, String name) {
this.salary = this.age + 1000;
this.name = "Tom";
this.salary += 500;
this.print();
this.salary = salary.intValue();
this.name = name;
this.print();
}
private void print() {
System.out.println("age=" + this.age);
System.out.println("salary=" + this.salary);
System.out.println("name=" + this.name);
}
public static Initialization construct(int salary, String name) throws Exception {
Constructor constructorWithNoParams = Initialization.class.getConstructor(new Class[0]);
Constructor constructorWithParams = Initialization.class.getConstructor(new Class[]{Integer.class, String.class});
return salary > 0 && name != null?(Initialization)constructorWithParams.newInstance(new Object[]{Integer.valueOf(salary), name}):(Initialization)constructorWithNoParams.newInstance(new Object[0]);
}
public Initialization deSerialize() throws Exception {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.txt"));
output.writeObject(this);
output.close();
ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.txt"));
return (Initialization)input.readObject();
}
public static void main(String[] args) throws Exception {
Initialization result = construct(0, "Paul");
}
}
1、无论实例变量还是实例代码块,均遵从先父类后子类的初始化顺序。
2、对实例变量直接赋值或者利用实例代码块赋值,编译器会其代码填充到类的构造函数中。不允许书写顺序靠前的实例代码初始化在其后定义的实例变量。
Java强制要求Object对象(Object是Java的顶层对象,没有超类)之外的所有对象构造函数的第一条语句必须是超类构造函数的调用语句或者是类中定义的其他的构造函数,如果我们既没有调用其他的构造函数,也没有显式调用超类的构造函数,那么编译器会为我们自动生成一个对超类构造函数的调用。这样确保当前对象完成初始化前其父类已完成初始化,从而构建完整的对象。
如果默认构造函数内部调用了有参构造函数,仅允许在有参构造函数里调用父类构造函数。
静态代码块
- 多个static按编码顺序依次处理
- static变量的申明和初始化是两个不同的操作
- static变量在编译期已确认值
以下代码是等价的:
// code list1
public class StaticInitialization {
static {
data = 1;
}
public static void main(String[] args) {
System.out.println(data);
}
private static int data = 2;
}
// code list 2
public class StaticInitialization {
private static int data;
static {
data = 1;
data = 2;
}
public static void main(String[] args) {
System.out.println(data);
}
}
code list 2的字节码为:
public class StaticInitialization {
public StaticInitialization();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field data:I
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: return
static {};
Code:
0: iconst_1
1: putstatic #3 // Field data:I
4: iconst_2
5: putstatic #3 // Field data:I
8: return
}
可以看到static变量在编译期就已放到常量const指向的内存地址里。
初始化顺序
如果没有继承关系,初始化顺序为:静态代码、静态代码块 > 成员变量、实例代码块 > 构造函数。否则,初始化顺序为先父后子。
所以初始化顺序:父类static静态变量 > 父类static代码块 > 子类static静态变量 > 子类static代码块 > 父类变量 > 父类实例代码块 > 父类构造函数 > 子类变量 > 子类实例代码块 > 子类构造函数
举个例子:
public class StaticTest {
public static void main(String[] args) {
staticFunction();
}
private static int data;
static StaticTest st;
static { //静态代码块
System.out.println("1");
}
{ // 实例代码块
System.out.println("2");
}
static {
data = 1;
}
static {
st = new StaticTest();
}
StaticTest() { // 实例构造器
System.out.println("3");
System.out.println("a=" + a + ",b=" + b);
}
public static void staticFunction() { // 静态方法
System.out.println("4");
}
int a = 110; // 实例变量
static int b = 112; // 静态变量
}
/**
* 输出结果
* 1
* 2
* 3
* a=110,b=0
* 4
*/

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
2018-06-12 第三十七天
一、线程安全 线程安全的问题,是针对多线程的程序。单线程的情况下,是不存在线程安全问题。 产生线程安全问题的原因:多个线程同时访问同一块代码。但是实际上我们希望该代码块是原子性的,在某一个时间点,只希望一个线程单独访问,不希望多个线程同时访问。 解决方案: 1:同步代码块。 synchronized(this) { //被同步的代码块; } synchronized(同步监视器对象):java 关键字 {}:同步代码块:希望在某一个时间点只有一个线程访问的代码块。 执行过程: 1:线程1 执行到了同步代码块。要对同步监视器进行检测,看是否被其他的线程上锁了。发现没有上锁,那么线程1对同步监视器对象 上锁,并开始访问 同步代码块。 2:线程2 执行到了同步代码块,检测同步监视器,发现监视器已经被 线程1 上锁了。就进入就绪状态,等待cpu 下次调度执行。 3:线程1 执行完毕同步代码块,然后对 同步监视器对象 解锁。并执行后续的代码。 4:当 线程2 被再次调度执行的时候,发现同步监视器对象已经被解锁,那么就对同步监视器对象 加锁 并访问 同步代码块。 类似于上厕所:没人(有人就等着),...
-
下一篇
Python socket 编程理解
HTTP 、Socket 、 TCP 七层OSI网络模型,这里只介绍五层常用网络模型,想知道全部七层详细内容自行查询。 应用层 :HTTP FTP SMTP DNS Telnet 传输层 :TCP UDP 网络层 :IP ICMP 数据链路层 :ARP等 物理层 :1000BASE-SX等 socket是用来连接传输层和应用层,使得应用层可以直接和传输层做交互。 socket本身不属于网络协议,socket可以直接操控tcp,这样可以实现自己的应用层协议,例如聊天室就是,socket可以直接和tcp打交道,实现与http同级别的网络协议。 image.png image.png 上图左侧是server端,右侧是client端
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境