构造函数
之前定义的函数都是一般函数。用于描述事物应该具备的功能。
构造函数:也是功能,只不过这个功能有点特殊,专门用于给对象进行初始化。
格式:
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
|
|