A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© x378320002 中级黑马   /  2013-6-17 08:18  /  2287 人查看  /  14 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

类在new对象时,是先加载成员变量,默认初始化,还是先调用构造函体啊?是不是成员变量默认初始化和成员变量赋值和调用super()都是隐含在构造
体里的,只是隐式的而已?
因为我觉得只调用了super(),就把父类完整初始化了,以前一直认为默认初始化
在构造函数之外呢

评分

参与人数 1技术分 +1 收起 理由
刘凯 + 1 赞一个!

查看全部评分

14 个回复

倒序浏览
不带参数的构造方法不管你写不写度会默认自动调用的,还有就是一般new一个类是先加载它的构造方法,
如果你在子类里面写super()就是调用父类的无参数的构造方法,你还可以super.方法()或者super.属性来调用父类里面公共的方法或属性。
如有说不对望楼主别见怪~
回复 使用道具 举报
1.主函数读到new关键字时,要创建对象。这时JVM会找到这个类的.class文件加载到内存中。
2.如果类中有构造代码块,那么先运行静态代码块,对类进行初始化。这个初始化只在类加载后运行一次。
3.在堆内存中分配空间,分配内存地址。
4.在堆内存中建立对象的特有属性,(进行默认初始化,这一步也就是楼主说的对类中的成员进行加载)。
5.对属性进行显示初始化。使该对象可以使用函数类的成员。
6.如果类中有构造代码块,则对对象进行构造代码块初始化。也就是对所有的对象进行一次统一的初始化。不过一般构造代码块很少使用。
7.对对象进行对应的构造函数的初始化。(如果该类继承了其他类,那么就先运行构造函数中的super(),对父类构造函数进行初始化)。
8.在栈内存中定义一个类类型的变量,并将该对象的内存地址赋给这个类变量。

这样一次new对象的初始化就完成了。加括号的两个地方应该能解释楼主的问题。希望能够帮到您。

评分

参与人数 1技术分 +1 收起 理由
刘凯 + 1

查看全部评分

回复 使用道具 举报
先加载成员变量, 后调用构造函数.
回复 使用道具 举报
shang1jk 发表于 2013-6-17 09:17
先加载成员变量, 后调用构造函数.

super需要自己写的吧, 应该不是隐式.
回复 使用道具 举报
shang1jk 发表于 2013-6-17 09:19
super需要自己写的吧, 应该不是隐式.

你写的super如果是super()语句的意思的话,那super()语句是隐式的,因为子类创建对象时候,会通过一条隐式的super()语句来调用父类的空参数的构造函数对父类进行初始化。只要当父类中没有空参数类型的构造函数时,子类才必须通过手写super()语句来指定要访问的父类中的有参的构造函数。
回复 使用道具 举报
王磊 发表于 2013-6-17 09:26
你写的super如果是super()语句的意思的话,那super()语句是隐式的,因为子类创建对象时候,会通过一条隐 ...

我是说子类构造函数中的super语句不可以省略, 对吧?不确定.

楼主问的是这种情况吧?

回复 使用道具 举报
王磊 发表于 2013-6-17 09:13
1.主函数读到new关键字时,要创建对象。这时JVM会找到这个类的.class文件加载到内存中。
2.如果类中有构造 ...

顺序是先调用super(),再对属性进行显示初始化吧,这个顺序我知道
我想知道的是这个super()里面包括了什么,这只是构造函数,但是却完整的初始化了
父类,所以我觉得对象特有属性建立啊赋值啊什么的应该都隐含在里面的。
回复 使用道具 举报
mulua 中级黑马 2013-6-17 12:47:11
9#
当需要用到某个类时,类加载器会自动加载该类,接着该类的静态代码块执行,对类进行初始化,然后调用构造代码块对所有的对象进行初始化,最后才调用构造函数对与之对应的对象进行初始化,
所以是先加载变量,后调用构造函数

评分

参与人数 1技术分 +1 收起 理由
孙百鑫 + 1

查看全部评分

回复 使用道具 举报
public class InitSequence {
        int x;                        //1.定义一个成员变量,此时已有默认值0
        String name ;        //2.定义一个String,默认值为空
        //3.初始化代码块
        {
                System.out.println("初始化代码块执行");
        }
        //4.静态代码块
        static{
                System.out.println("静态初始化代码块执行");
        }
        //5.无参构造函数
        public InitSequence() {
                super();                //6.不写时是默认的,必须放在构造函数第一行,调用的是Object的构造函数
                name = "张三";        //7.改变name值
                System.out.println("构造函数执行 name = " + name);
        }
        //8.一个参数构造函数
        public InitSequence(String name) {
                this();
                this.name = name;
                System.out.println("带有name的构造函数执行");
        }
        public static void main(String[] args) {
                InitSequence init = new InitSequence("李四");
                System.out.println("x  =  " + init.x);
                System.out.println("name  =  " + init.name);
        }
}
执行结果是:
静态初始化代码块执行
初始化代码块执行
构造函数执行 name = 张三
带有name的构造函数执行
x  =  0
name  =  李四
程序执行顺序是:静态初始化快-->初始化块-->构造函数,定义成员变量时,java会赋默认值,int为0 ,boolean为false,String 为null,在无直接父类的情况下,类的默认构造会隐式调用Object的构造函数,构造函数的功能是对已定义的成员变量进行具有意义的赋值,比如成员变量name,定义是的默认值为null,如果有人不小心打印了name,则会输出name = null,这样普通人是看不懂的,所以应该在定义name的时候初始化为" ",在给name指定有意义值的时候,就用InitSequence(String name);

评分

参与人数 1技术分 +1 收起 理由
刘凯 + 1 赞一个!

查看全部评分

回复 使用道具 举报
首先,成员变量作用于整个类中 局部变量作用于函数中,或语句中
  1. public class Person {  
  2.     private String name="zhangsan";  
  3.     private int age;  
  4.     private static String country = "cn";  
  5.     {  
  6.         System.out.println("name"+name+"age:"+age);  
  7.     }  
  8.     Person(String name, int age) {  
  9.         this.name = name;  
  10.         this.age = age;  
  11.     }  
  12.   
  13.     public void setName(String name) {  
  14.         this.name = name;  
  15.     }  
  16.   
  17.     public void speak() {  
  18.         System.out.println(this.name + ".." + this.age);  
  19.     }  
  20.   
  21.     public static void showCountry() {  
  22.         System.out.println("country=" + country);  
  23.     }  
  24. }  
复制代码
Person p=new Person("zhang",20);

      该句话都做了什么事情?

          1,因为new 用到了Person.class所以会先找到Person.class文件并加载到内存中。

          2,会执行该类中的静态代码块,如果有的话,给Person.class类进行初始化

          3,在堆内存中开辟空间,分配内存地址。

          4,在堆内存中建立对象的特有属性。并进行默认初始化。

          5,对属性进行显示初始化

          6,对对象进行构造代码块初始化

          7,对对象进行对应的构造函数初始化

          8,将内存地址赋给栈内存的p变量

评分

参与人数 1技术分 +1 收起 理由
刘凯 + 1 赞一个!

查看全部评分

回复 使用道具 举报
x378320002 发表于 2013-6-17 12:42
顺序是先调用super(),再对属性进行显示初始化吧,这个顺序我知道
我想知道的是这个super()里面包括 ...

个人感觉,super()语句的作用在对父类进行初始化时,就好像是在子类中隐式的创建了一个父类对象,然后在子类中通过这个父类对象对其成员进行调用。也就是说创建子类的时候,按这8条流程走了一边,然后走到构造函数的时候,因为调用了super()语句,所以这时又对父类的隐式对象把这8条流程走一遍。所以感觉楼主说的其实也对,不过更确切的说应该的顺序应该是:1.子类成员,2.子类构造函数,3.父类成员,4.父类构造函数,5.子类对象地址赋给变量。如果按1·2来看,就是正常说的顺序,看2~3的话,就是楼主说的顺序,只不过说面向的对象是不同的。
回复 使用道具 举报
如果父类没有自己编写构造方法的话,父类会默认一个构造方法。此时子类定义构造方法时可以省略掉super();否则如果子类要调用父类已经编号的构造方法时,必须使用super()调用。
super关键字1)显式的调用父类的方法当从一个类继承时,子类和父类都有一个同名方法,也就是子类覆盖了父类的方法,可是又想调用父类的方法,那么就要用super,像继承swing的类时就有个好例子public class MyPanel extends JPanel {   @Override   public void paint(Graphics g) {       super.paint(g);//如果不用super,那么就会调用自己的paint方法   }}2)用在构造器,和this的用法一样,super也可以用在构造器,this是调用自己的其他构造器,那么super当然就是调用父类的构造器了 -------------------------------------------------------super和this用在构造器的话,前者表示调用父类的够早器,后者表示调用本类的其他构造器,他们两个都必须是写在构造器里的第一行public class Person {   private String name;   private int age;   public Person() {       name = "";       age = 0;   }   public Person(String n, int a) {       name = n;       age = a;   }}public class Student extends Person {   private String id;//学号   public Student(String name, int age) {       super(name, age);//必须写在第一行,子类无法直接访问父类的私有属性,所以通过调用父类的构造器类初始化属性   }   public Student(String id, String name, int age) {       this(name, age);//因为本类已经有个构造器初始化name和age了,所以交给他来做就行了,也必须写在第一行       this.id = id;   }}
回复 使用道具 举报
shang1jk 发表于 2013-6-17 10:34
我是说子类构造函数中的super语句不可以省略, 对吧?不确定.

楼主问的是这种情况吧?

我错了, 可以省略, 隐式的..
回复 使用道具 举报
楼主您好~帖子长时间未作出回答,我已经将您的帖子改成已解决。如果有问题的话可以私密我哦~
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马