面向对象
类
package com.mm;public class Person {/*** 名词-属性*/String name;int age;double height;/*** 动词-方法*/public void sleep(String add) {System.out.println("我在" + add + "睡觉");}public String introduce() {return "我的名字是" + name + "我的年龄是" + age;}
}
调用Person类
package com.mm;/*** 测试类:一般在测试类中编写业务逻辑代码*/
public class test {/*** main程序的入口*/public static void main(String[] args) {//创建一个Person类的对象Person p1 = new Person();//参照类的模板,给对象赋值p1.name = "丽丽";p1.age = 19;p1.height = 164.7;p1.sleep("宾馆");//接收对象返回值String s = p1.introduce();System.out.println(s);//创建新对象,对象不能重复命名Person p2 = new Person();p2.age = 30;//匿名对象new Person().age = 10;//可以对对象的属性进行赋值//注意,重复调用匿名对象产生的是不同对象,这是一个新的对象new Person().name = "菲菲";//用于仅一次调用,支持链式调用。表示返回下标为1的字符new Person().introduce().charAt(1);System.out.println(new Person().introduce().charAt(1));}
}
构造器
package com.mm;public class Person {/*** 名词-属性*/String name;int age;double height;/*** 显式的将构造器编写出来*/public Person(){System.out.println("这是无参构造器");}/*** 动词-方法*/public void sleep(String add) {System.out.println("我在" + add + "睡觉");}public String introduce() {return "我的名字是" + name + "我的年龄是" + age;}
}
调用Person类
package com.mm;/*** 测试类:一般在测试类中编写业务逻辑代码*/
public class test {/*** main程序的入口*/public static void main(String[] args) {Person p = new Person();}
}
有参构造器——构造器的重载
package com.mm;public class Person {int age;String name;double height;public Person(){//空参构造器,尽量保证存在}//构造器的重载public Person(int age, String name, double height) {//形参名可以跟属性一样,//默认就近原则:下面两个age都默认是形参age,相当于没有赋值给属性this.age = age;//使用this关键字,修饰要表示的属性this.name = name;this.height = height;}
}
调用Person类
package com.mm;public class test {public static void main(String[] args) {Person p = new Person(1, "菲菲", 110.1);System.out.println(p.age);System.out.println(p.name);}public static void main(String[] args) {Person p = new Person(2, "琳琳", 120.1);System.out.println(p.age);System.out.println(p.name);
}
步骤1
在栈中为main方法开辟栈帧。把Person类对应的字节码信息加载到方法区。等号右侧:new操作在堆空间开辟空间创建对象,此时属性为初始值。
步骤2
调用有参构造器(在构造方法栈中产生有参构造方法的栈帧,含参数a、b、c)。JVM(从栈内存?)把基本数据类型通过值传递传给a、b,从字符串常量池把字符串(地址)传给参数c。
步骤3
构造方法栈帧中的a、b、c把对应值传给堆中的对象属性。构造方法栈帧消失。
步骤4
堆空间中生成一个对应的地址0x88。等号左侧:把地址赋给栈空间中main栈帧的对象p
内存分析
方法形参为自定义引用数据类型。对象和对象之间的数据本身是不会相互影响的,但多个变量指向同一个对象时就会相互影响
package com.mm;public class Person {int id;int age;Person(int a, int b) {id = a;age = b;}class Test {public void change(Person p) {//传递对象p(不是传递对象的数据)p.id = 2;p.age = 18;}public static void main(String[] args) {//主方法Person p = new Person(1, 20);//创建对象p(0x88地址指向堆内存中的对象)Test t = new Test();//创建对象t(0x72地址指向堆内存中的对象)t.change(p);//t调用change方法。为change方法创建对应栈帧,把main方法里的对象p传到chage方法里(虽然是通过值传递方式,但传过去的也是0x88地址指向堆内存中的对象)System.out.println(p.id);//2System.out.println(p.age);//18}}
}
步骤1
在栈中为main方法开辟栈帧。
把Person类对应的字节码信息加载到方法区。等号右侧:new操作在堆空间开辟空间创建对象,此时属性为初始值。堆空间中生成一个对应的地址0x88。等号左侧:把地址赋给栈空间中main栈帧的对象p
把Test类对应的字节码信息加载到方法区。等号右侧:new操作在堆空间开辟空间创建对象,此时属性为初始值。堆空间中生成一个对应的地址0x72。等号左侧:把地址赋给栈空间中main栈帧的对象t
步骤2
在栈帧中开辟change方法栈帧,并将p对象的地址提供‘值传递’方式传到change方法栈帧。
步骤3
change栈帧中的p依旧是0x88,指向堆空间里的对象
方法形参为自定义引用数据类型。对象和对象之间的数据本身是不会相互影响的,但多个变量指向同一个对象时就会相互影响
步骤4
方法change对p.id和p.age重新赋值,改变堆空间0x88对应的对象p的属性
打印时main栈帧里的p对象通过0x88找到堆空间的p对象并返回属性值(被改变)
this关键字
package com.mm;public class Person {int age;String name;public Person(int age, String name){//属性名字和形参重名//this修饰构造器必须放在第一行this(age);//等于this.age = age。相当于调用本类的构造器(下面第一个)System.out.println(this); // 指代的就是当前正在构建的对象//this.age = age; // 如果属性名字和形参重名,那么要表示的属性前面必须加上thisthis.name = name;}public Person(int age){//被this隐式修饰的构造器,被上面调用this.age = age;}public Person(String name){//参数类型不同,不会被调用this.name = name;}public void sleep(){System.out.println(/*this.*/age); // 10,此处没有重名问题,那么可以省略this.int age = 66;System.out.println(age);//66 如果局部变量和属性重名,也会发生就近原则System.out.println(this.age); // 10}public void eat(){System.out.println(this); // 指代的就是正在调用当前方法的对象System.out.println("我可以吃饭");play();//如果在同一个类中调用本类的方法,可以不用写this}public void play(){System.out.println("我可以玩");}
}
调用Person类sleep方法
package com.mm;public class Test {public static void main(String[] args) {// 创建Person类的具体的对象:Person p = new Person(10, "丽丽");System.out.println(p);p.sleep();p.eat();}
}
封装
package com.mm;public class Person {private int age;/*** 定义一个方法,用来设置age,提供合理的暴露*/public void setAge(int age) {if (age >= 18) {//只暴露小于18的,大于等于18的都是18this.age = 18;} else {this.age = age;}}/*** 用来读取age*/public int getAge() {return this.age;}
}
调用Person
package com.mm;public class test {public static void main(String[] args) {Person p = new Person();p.setAge(19);System.out.println(p.getAge());}
}
封装实操
package com.mm;public class Person {private String name;private String sex;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {if (sex.equals("男") || sex.equals("女")) {//使用equals更规范this.sex = sex;} else {this.sex = "男";}}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person() {}public Person(String name, String sex, int age) {this.name = name;//相当于this.sex = sex;setSex(sex);//使用上面的方法setSexthis.age = age;}
}
调用Person类
package com.mm;public class test {public static void main(String[] args) {Person p = new Person();p.setAge(19);p.setName("丽丽");p.setSex("女");System.out.println(p.getAge());System.out.println(p.getName());System.out.println(p.getSex());Person p2 = new Person("菲菲", "sdfa", 19);System.out.println(p2.getAge());System.out.println(p2.getName());System.out.println(p2.getSex());}
}