Java零基础入门:从封装到构造方法 --- OOP(上)
B站:【黑马程序员Java零基础视频教程_上部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)】https://www.bilibili.com/video/BV17F411T7Ao?vd_source=902cae974409091c868112996a85ad70
一. 面向对象
二. 类和对象
比如:
三. 封装
1 封装
面向对象的三大特征:封装、继承、多态
举一个栗子:
2 private 关键字
以刚才的 GrilFriend 为例:
当年龄被意外修改为 -18 时,程序仍会运行显示年龄为 -18 岁,很显然这是不符合实际的,为了不让外部随意赋值,导致数据不合法确被储存,我们引入了 private 关键字
我们发现,用了 private 后,正确的值也无法运行,这不是我们想要的结果。期待的结果是:正确的可以赋值,错误的无法赋值。因此我们添加了判断语句来确保数据的合法性:
完整的代码就是下面这样了:
GrilFriend.java
package practice.daily;public class GrilFriend {//属性private String name;private int age;private String gender;//针对于每一个私有化的成员变量,都要提供get和set方法//set方法:给成员变量赋值//get方法:对外提供成员变量的值//给成员变量name进行赋值public void setName(String n) {name = n;}//对外提供name属性public String getName() {return name;}//给成员变量age进行赋值public void setAge(int a) {if (a >= 18 && a <= 50) {age = a;} else {System.out.println("输入的年龄为非法参数");}}//对外提供age属性public int getAge() {return age;}//给成员变量gender进行赋值public void setGender(String g) {gender = g;}//对外提供gender属性public String getGender() {return gender;}//行为public void sleep() {System.out.println("女朋友在睡觉");}public void playGame() {System.out.println("女朋友在玩游戏");}
}
GrilFriendTest.java
package practice.daily;public class GrilFriendTest {public static void main(String[] args) {//创建女朋友的对象GrilFriend gf1 = new GrilFriend();//给女朋友的对象赋值gf1.setName("小美");gf1.setAge(18);gf1.setGender("女");System.out.println(gf1.getName());System.out.println(gf1.getAge());System.out.println(gf1.getGender());//调用女朋友的方法gf1.sleep();gf1.playGame();}
}
小结:
四. 就近原则和 this 关键字
1. 成员变量和局部变量
2. 就近原则
如果我们不想打印10,而是想使用成员位置的 age ,那么就需要用到 this 关键字了
3. this 关键字
this 的作用:区分成员变量和局部变量
运行结果就是 0
这样,我们的 GrilFriend 类就可以进一步优化了 --- 将 n、a、g 修改为 name、age、gender ,并使用 this 关键字:
五. 构造方法
小结:
以学生为例举一个例子:
Student.java
package practice.daily.test4;public class Student {private String name;private int age;//如果我们自己没有写任何的构造方法//那么虚拟机会给我们加一个空参构造方法//空参构造方法public Student() {System.out.println("空参构造方法");}//带参构造方法public Student(String name,int age) {this.name = name;this.age = age;}// public void setName(String name) {
// this.name = name;
// }public String getName() {return name;}// public void setAge(int age) {
// this.age = age;
// }public int getAge() {return age;}
}
StudentTest.java
package practice.daily.test4;public class StudentTest {public static void main(String[] args) {//创建对象,调用空参构造//Student s = new Student();//创建对象,调用带参构造Student s = new Student("zhangsan", 18);System.out.println(s.getName());System.out.println(s.getAge());}
}
六. 标准的 javabean 类
以下面这个界面为例:
User.java
package practice.daily.test5;public class User {//属性private String username;private String password;private String email;private String gender;private int age;//空参构造public User() {}//带全部参数构造public User(String username, String password, String email, String gender, int age) {this.username = username;this.password = password;this.email = email;this.gender = gender;this.age = age;}//get和set方法public void setUsername(String username) {this.username = username;}public String getUsername() {return username;}public void setPassword(String password) {this.password = password;}public String gerPassword() {return password;}public void setEmail(String email) {this.email = email;}public String getEmail() {return email;}public void setGender(String gender) {this.gender = gender;}public String getGender() {return gender;}public void setAge(int age) {this.age = age;}public int getAge() {return age;}
}
UserTest.java
package practice.daily.test5;public class UserTest {public static void main(String[] args) {/* //创建User对象,调用空参构造User user = new User();//调用set方法,赋值user.setUsername("张三");user.setPassword("123456");user.setEmail("zhangsan@126.com");user.setGender("男");user.setAge(18);//调用get方法,打印System.out.println("用户名:" + user.getUsername());System.out.println("密码:" + user.gerPassword());System.out.println("邮箱:" + user.getEmail());System.out.println("性别:" + user.getGender());System.out.println("年龄:" + user.getAge()); *///创建User对象,调用带参构造User user = new User("张三", "123456", "zhangsan@126.com", "男", 18);//调用get方法,打印System.out.println("用户名:" + user.getUsername());System.out.println("密码:" + user.gerPassword());System.out.println("邮箱:" + user.getEmail());System.out.println("性别:" + user.getGender());System.out.println("年龄:" + user.getAge());}
}
运行结果:
七. IDEA快捷键
生成构造方法:alt + insert (或 alt + Fn + insert) -> Constructor -> 1. Select None(空参构造方法);2. Ctrl + A 全选(带全部参数的构造方法)
生成 set 和 get 方法:alt + insert -> Getter and Setter -> Ctrl + A 全选
插件 PTG (1秒生成标准 Javabean):右击空白处 -> Ptg To Javabean
八. 对象内存图
1. Java 内存分配介绍
2. 一个对象的内存图
整个过程:
1. "public class TestStudent":测试类 TsetStudent 被加载到方法区,main() 方法进行临时存储;"public static void main(String[] args)":虚拟机调用 main 方法, main 方法会被加载进栈
2. "Student s = new Student ()":创建一个对象 ---
1.加载class文件:Student.class 被加载到方法区进行临时存储,这里面会存储 Student 这个类的所有信息,比如所有的成员变量 name、age 和所有的成员方法 study() ;2. 申明局部变量:”Student s“,在 main 方法中会开辟一个空间,这个空间的名字就叫 s ,这个空间以后能存储 Student 这个对象的地址值;3. 在堆内存中开辟一个空间:"new Student()",堆内存中开辟一个小空间,地址值为001,这个空间就会把 Student 类里面的所有的成员变量拿出来拷贝一份,还会有成员方法的地址 (为了以后调方法时能找到对应的方法);4. 默认初始化:成员变量初始化为默认值:name = null, age = 0;5. 显式初始化:如果定义成员变量时直接给了值,就叫显式初始化,本代码中并没有赋值,因此不涉及该步;6. 构造方法初始化:"new Student()" 的括号中什么都没写,用的是空参构造,而代码的空参构造中没有写代码,因此该步也略掉;但如果用有参构造的话,此时 name 和 age 就有对应值了;7. 将堆内存中的地址值赋值给左边的局部变量:将堆内存中的对象地址001赋值给栈内存的 main 方法中创建的局部变量 s,s 也就可以通过001找到堆内存中对应的空间
3. "System.out.println (s)":println 方法的栈帧进入栈内存,输出堆内存中 Student 对象的地址引用(即打印对象地址001),栈帧出栈
4. "System.out.println (s.name +"..."+ s.age)":println(s.name + ". . . " + s.age) 进入栈内存,通过 s 找到堆中对象,获取 name = null 和 age = 0,打印 null...0,栈帧出栈
5. "s.name =" 阿强 "; s.age = 23":赋值操作进入栈内存执行;堆内存中对象的name属性更新为"阿强",age属性更新为23
6. "System.out.println (s.name +"..."+ s.age)":println(s.name + ". . . " + s.age) 进入栈内存,获取修改后的值,打印阿强...23,栈帧出栈
7. "s.study ()":study () 方法的栈帧进入栈内存,执行方法体(打印 "好好学习"),栈帧出栈
8. main 方法执行完毕,其栈帧出栈
9. 栈中无变量指向堆中 001 地址,该对象成为垃圾,等待垃圾回收机制清理
2. 两个对象的内存图
堆内存的两个小空间是互不影响的;在执行第二个对象时,不会再加载一遍 class 文件
3. 两个引用指向同一个对象
上图中,堆内存中的内容变成垃圾
敲重点:
当两个变量指向同一个空间时,只要有其中一个变量对这个空间的值发生了改变,那么其他变量再次访问时,就是改变之后的结果
九. 基本数据类型和引用数据类型
十. this 的内存原理
this 的作用:区分局部变量和成员变量
this 的本质:所在方法调用者的地址值
"this.name = name" :把“竹小玲”赋值给001里的 name
方法执行完后出栈