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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

构造函数

之前定义的函数都是一般函数。用于描述事物应该具备的功能。
构造函数:也是功能,只不过这个功能有点特殊,专门用于给对象进行初始化。
格式:
1.函数名和类名相同。
2.没有返回值类型。
3.没有具体的返回值。

一般函数和构造函数的区别?
运行上的区别?
构造函数在对象创建对象时就执行了。而且只执行了一次。
一般函数是在对象创建后,需要时才被对象调用,可以调用多次。
多构造函数在类中的就是重载形式。

class Person
{   
    private String name;
    private int age;
    /**
    定义一个构造函数,用于给person对象初始化,
    person对象一初始化就可以有姓名和年龄。
    */
    Person(String n,int a)
    {
           name=n;
           age=a;
    }
    public void setName(String n)
    {
       name=n;
     }
     public String getName()
     {
     return name;
     }
     public void setAge(int a)
    {
       age=a;
     }
     public int getAge()
     {
     return age;
     }
}
    public  void show()
    {
      System.out.println("name="+name+",age="+age);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class PersonDemo
{
   public static void main(String[] args)
   {
   //创建一个Person对象。需求:描述事物符合现实生活,Person对象一建立就有性别和年龄。
   //相当于要对对象进行初始化。怎么来实现?Java中的构造函数就可以解决该问题。
   Person p=new Person("wangcai",20);
   p=new Person("wangwang",21);//改名字和年龄
  // p.setName("xiaoqiang")
  // p.setAge(20);
   p.show();
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
构造函数内存图


默认构造函数

当签new对象时,也没有构造函数。那这个对象是怎么初始化的?
注意1:定义的每一个类中,都有一个默认的空参数构造函数。
注意2:一旦在类中自定义了构造函数后,默认的构造函数就没有了。
如下:

class Car
{
   //Car(){}//类中默认的空参构造函数,专门用于创建对象初始化用的。
}
class CarDemo
{
      main()
      {
        Car c=new Car();
     }
}
1
2
3
4
5
6
7
8
9
10
11
那如果自定义了构造函数,那就不可以 Person p=new Person();了。这时候可以再定义一个空参构造函数。

class Person
{   
    private String name;
    private int age;
     Person()//再定义的空参构造函数
    {
           name=baby;
    }
    Person(String n,int a)
    {
           name=n;
           age=a;
    }
    public void setName(String n)
    {
       name=n;
     }
     public String getName()
     {
     return name;
     }
     public void setAge(int a)
    {
       age=a;
     }
     public int getAge()
     {
     return age;
     }
}
    public  void show()
    {
      System.out.println("name="+name+",age="+age);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class PersonDemo
{
   public static void main(String[] args)
   {
   Person p=new Person();
   p.show();
   }
}
1
2
3
4
5
6
7
8
构造函数细节

1.构造函数中有return语句么?有,用于结束初始化。
2.

class Person
{
    void Person()//一般函数。可以存在的,但不符合书写规范。一般方法的首字母应该是小写。
    {
    }
    void showPerson(){}
}
1
2
3
4
5
6
7
3.私有构造函数
构造函数可以私有化。只在本类中使用。
而且构造函数一旦私有化,其他程序就无法创建该类的对象。
原因:无法对创建的对象进行初始化。

class Person
{   
    private String name;
    private int age;
    private Person(String n,int a)
    {
           name=n;
           age=a;
    }
1
2
3
4
5
6
7
8
9
那这样如何在本类中调用私有化的构造函数?

构造函数调用

class Person {
            private String name;
            private int age;        
            Person(){
                  name="baby";                   
            }            
            private Person(String n){
                   name=n;                   
            }
            /*
             构造函数私有,只在本类中有效。该如何访问呢?
             注意1:构造函数只能被构造函数调用,不能直接被一般方法调用。
             构造函数之间该如何访问呢?通过关键字this来解决。
            
            this:代表的是对象。代表哪个对象呢?哪个对象调用this所在的函数,this就代表哪个对象。
            this带上参数列表的方式就是可以访问本类中的其他构造函数,
            比如:this("list");访问的就是本类中,带一个字符串参数的构造函数。
            
            记住:用于调用构造函数的this语句必须定义在构造函数的第一行。因为初始化动作要先执行。
            一个构造函数中不能调用两个调用this函数。
            如果两个构造函数互相用this调用,则会产生递归,递归次数多了最后溢出。
             */
            Person(String n,int a){
                       this(n);
                   //name=n;
                   age=a;
            }                     
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }            
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class PersonDemo {
         public static void main(String[] args)
           {          
           Person p=new Person("小明",20);                   
           p.show();
           }
}
1
2
3
4
5
6
7

this(n)调用了 private Person(String n){ name=n;}


如果增加 Person p=new Person(“小红”,20);       


this关键字区分变量同名

总结:只要直接被对象调用的方法都持有this引用。(凡是访问了对象中的数据的方法都持有this引用。)

class Person {
            private String name;
            private int age;        
        Person(String name,int age){
                       name=name;
                   age=age;
            }               
             public void show()
            {
              System.out.println("name="+name+",age="+age);
            }   
}

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PersonDemo {
         public static void main(String[] args)
           {          
           Person p=new Person("小明",21);                   
           p.show();  
           }
}       
1
2
3
4
5
6
7
当成员变量和局部变量相同时,其实在局部变量赋给局部变量,局部变量的值没有传递到成员变量中,所以输出的为

name=null,age=0;
1
如果想传递到则把

class Person {
            private String name;
            private int age;        
        Person(String name,int age){
                       name=name;
                   age=age;
            }       
             public void show()
            {
              System.out.println("name="+name+",age="+age);
            }             
}
1
2
3
4
5
6
7
8
9
10
11
12
改为

class Person {
            private String name;
            private int age;        
        Person(String name,int age){
                       this.name=name;
                  this.age=age;
            }                     
             public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
}
1
2
3
4
5
6
7
8
9
10
11
12

总结:当成员变量和局部变量同名时,可以通过this关键字区分。
或者可以这样写:

class Person {
            private String _name;
            private int _age;        
        Person(String name,int age){
                       _name=name;
                   _age=age;
            }                     
             public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
方法的话:

class Person {
            private String name;
            private int age;        
        Person(String name,int age){
                       name=name;
                   age=age;
            }                     
             public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
             public void method()
            {
              this.show();//这里的this可以省略
            }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PersonDemo {
         public static void main(String[] args)
           {          
           Person p=new Person("小明",21);                   
           //p.show();  
           p.method();  
           }
}       
1
2
3
4
5
6
7
8
this关键词的应用

需求:建立功能,判断是否是同龄人。
结果:boolean
参数:传递一个Person对象。

class Person {
            private String name;
            private int age;

            Person(String n,int age){
                       //this(n);
                   this.name=name;
                   this.age=age;
            }
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
            public boolean equalsAge(Person pp)
            {
                    /*
                    if(pp.age==this.age)
                            return true;
                    return false;
                    */           
                    return pp.age==this.age;
                    //return pp==this;//这句话的意思是局部变量和对象成员变量的地址是否相同。也就是说这两个人是否为同一个人。
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PersonDemo {
         public static void main(String[] args)
           {          
           Person p=new Person("wangcai",20);                   
           Person pp=new Person("xiaoqiang",21);
           boolean a=p.equalsAge(pp);
           System.out.println(a);          
           }  
}
1
2
3
4
5
6
7
8
9
静态方法

static:用于修饰成员的静态关键字。
什么时候函数需要静态修饰?
该函数没有访问过对象的属性时。就需要用静态修饰。

class Person {
            private String name;
            private int age;            
            Person(String name,int age){
                       //this(n);
                   this.name=name;
                   this.age=age;
            }
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
            /*
            既然sleep方法没有访问到对象中的特有数据。
            都可以不需要对象就可以使用该方法,只要在该方法上用static修饰即可。
            */
            public static void sleep()
            {
                    System.out.println("呼呼");                   
            }   
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class StaticDemo {
         public static void main(String[] args)
           {          
           /*
           如果创建对象调用sleep方法。
           发现:sleep并没有使用对象中的数据。
           该对象的建立是没有意义的。
          
          该方法所属于Person.class。
          可以通过类名的方式来访问。
          注意:用类名直接调用的方法必须通过指定修饰符来修饰。就是关键字static。在上一个类中public static void sleep。
           */
           Person p=new Person("wangcai",20);                   
//           p.show();
//           p.sleep();
//改成
          Person.sleep();
           }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

sleep()和show()的区别就是 sleep()很多余,那么建立的对象平白占了堆的空间,和name、age无关。

静态变量

class Person {
            private String name;
            private int age;            
            String country="CN";//创建一个国籍成员
            Person(String name,int age){
                       //this(n);
                   this.name=name;
                   this.age=age;
            }
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
每个人的国籍都是同一个,所以可以把共同的拎出来。


改成


在代码中的体现:

class Person {
            private String name;
            private int age;            
            static String country="CN";//创建一个国籍成员
            Person(String name,int age){
                       //this(n);
                   this.name=name;
                   this.age=age;
            }
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PersonDemo {
         public static void main(String[] args)
           {          
           Person.sleep();
           System.out.println(Person.country);//用类名直接调用变量
           }  
}       
1
2
3
4
5
6
7
静态特点

静态关键字static:
是什么?
成员修饰符。
有什么特点:
1.被静态修饰的成员,可以直接被类名所调用。
2.静态成员优先于对象存在。
3.静态成员随着类的加载而加载。随着类的消失而消失。静态成员生命周期很长。



sleep()里没有this了,因为这里是Person.sleep()静态调用,没有建立对象。


静态使用注意事项

1.静态方法只能访问静态成员,不能访问非静态成员。这就是静态方法的访问局限性。
2.静态的方法中不能出现this或者super关键字。
3.主函数是静态的。

怎么用?
直接用于修饰成员。

什么时候用?
成员变量:如果数据在所有对象中的都是一样的。直接静态修饰。
成员函数:如果函数没有访问过对象中的属性数据。那么该函数就是静态的。

class Person {
            private String name;
            private int age;            
            static String country="CN";//创建一个国籍成员
            Person(String name,int age){
                       //this(n);
                   this.name=name;
                   this.age=age;
            }
            public void show()
            {
              System.out.println("name="+name+",age="+age);
            }
            static public void sleep()
            {
            System.out.println("呼呼……"+country); // 可不可以直接在这里+country?可以,因为在同一个静态方法区。
                                                 //不能+name,因为sleep()和name不在同一个静态方法区。会报错
                                               //Cannot make a static reference to the non-static field name无法从静态上下文中引用非静态变量name
           }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
为什么main函数前要加static

成员变量与静态变量的区别

1.名称上的区别?
成员变量也叫实例变量。
静态变量也叫类变量。
2.内存存储上的区别?
成员变量存储到堆内存的对象中。
静态变量存储到方法区的静态区中。
3.生命周期不同。
成员变量随着对象的出现而出现,随着对象的消失而消失。
静态变量随着类的出现而出现,随着类象的消失而消失。

(成员变量可能在类中出现多次,因为多次建立对象,则对应的成员变量就出现多次
静态变量前出现public,比如public static String country=“CN”,则表示为全局变量)

静态代码块

随着类的加载而执行,而且只执行一次。
作用:给类进行初始化。
应用场景:先不需要创建对象,但是需要初始化。这是将部分代码存储到静态代码块中。
第一种:

class StaticCode
{
     static//静态代码块
     {
        System.out.println("A")
     }
     static  void show()
     {
        System.out.println("show run")
     }
}
1
2
3
4
5
6
7
8
9
10
11
public class StaticDemo {
         public static void main(String[] args)
           {          
           StaticCode.show();
           StaticCode.show();
           }
}
1
2
3
4
5
6
7
结果:

A
show run
show run
1
2
3
第二种:

class StaticCode
{
     static//静态代码块
     {
        System.out.println("A")
     }
     static  void show()
     {
        System.out.println("show run")
     }
}
1
2
3
4
5
6
7
8
9
10
11
public class StaticDemo {
      static
     {
            System.out.println("B");                   
     }
         public static void main(String[] args)
           {          
           StaticCode.show();
           StaticCode.show();
           }
           static
     {
            System.out.println("C");                   
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
结果:

B
C
A
show run
show run
1
2
3
4
5
先静态 后函数运行。静态优先于对象存在。

构造函数代码块&对象的初始化流程

构造函数代码块

第一种:

class Person {
            private int age;
            
            {//构造代码块,给所有对象进行初始化。构造函数只给对应的对象进行初始化。
                    System.out.println("constructor code run");
                    cry();
            }
            
            Person()
            {
                    System.out.println("person run");
            //        cry();
            }  
            Person(int age)
            {
                    this.age=age;
                    System.out.println("Person(age) run");
            //        cry();
            }   
            public void cry()
            {
                    System.out.println("哇哇哇");
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ConsCodeDemo {
       
         public static void main(String[] args)
           {          
           Person p=new Person();
           Person p1=new Person();
           Person p2=new Person(4);          
           }
}
1
2
3
4
5
6
7
8
9
结果:

constructor code run
哇哇哇
person run
constructor code run
哇哇哇
person run
constructor code run
哇哇哇
Person(age) run
1
2
3
4
5
6
7
8
9
在每一个对象调用前都先“constructor code run,哇哇哇”

对象的初始化流程

创建一个对象的流程:
1.加载指定的字节码文件进内存。
2.通过new在堆内存中开辟空间。分配首地址值。
3.对对象中的属性进行默认初始化。
4.调用与之对应的构造函数。构造函数压栈。
5.构造函数中执行隐式的语句super()访问父类中的构造函数。
6.对属性进行显示初始化。
7.调用类中的构造代码块。
8.执行构造函数中自定义的初始化代码。
9.初始化完毕,将地址赋值给指定的引用。
第二种:
如果先 private int age=8;并且在构造函数块中+age,结果怎么样?

class Person {
            private int age=8;   
            {
                    System.out.println("constructor code run"+age);
                    cry();
            }
            
            Person()
            {
                    System.out.println("person run");
            }  
            Person(int age)
            {
                    this.age=age;
                    System.out.println("Person(age) run");;
            }   
            public void cry()
            {
                    System.out.println("哇哇哇");
            }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
结果:

constructor code run8
哇哇哇
person run
constructor code run8
哇哇哇
person run
constructor code run8
哇哇哇
Person(age) run
1
2
3
4
5
6
7
8
9
说明在构造函数之前age=8就存在。


局部代码块

局部代码块。可以控制局部变量的生命周期

public class ConsCodeDemo {
       
         public static void main(String[] args)
           {          
           Person p=new Person();
           Person p1=new Person();
           Person p2=new Person(4);          
           }
           int x=3;//这个不能放进下面的局部代码块中,否则会报错。
           {//局部代码块
           System.out.println("hehe");
           }
            System.out.println("x="+x);
}
---------------------
【转载】仅作分享,侵删
作者:ChunyeLi
原文:https://blog.csdn.net/sinat_32512123/article/details/84929197


2 个回复

倒序浏览
奈斯
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马