封装和继承

1. 封装

1.1 概念和思想

思想:我们之前直接使用等号给属性赋值,这样非常不合理,如果用户赋值了一些错误的值,我们没有机会去处理,相当于程序有比较高的耦合度,我们应该降低程序的耦合度,使用封装来解决。

封装 : 1.将类的信息尽可能的隐藏在类的内部 不让外部直接访问 使用private修饰属性即可 被private修饰的属性表示只能在本类中访问 其他类不能访问

2.而是提供一对公开的getter和setter方法用于访问属性

  1. package com.qfedu.test1;
  2. /**
  3. * 企鹅类
  4. *
  5. * 健康值
  6. * 名字
  7. * 性别
  8. *
  9. * 封装 :
  10. * 1.将类的信息尽可能的隐藏在类的内部 不让外部直接访问
  11. * 使用private修饰属性即可
  12. * 被private修饰的属性表示只能在本类中访问 其他类不能访问
  13. * 2.而是提供一对公开的getter和setter方法用于访问属性
  14. * getter方法用于获取属性值
  15. * setter方法用于设置属性值
  16. * @author WHD
  17. *
  18. */
  19. public class Penguin {
  20. private int health;
  21. private String sex;
  22. private String name;
  23. public int getHealth(){
  24. return health;
  25. }
  26. public void setHealth(int health) {
  27. if(health >=0 && health <= 100) {
  28. this.health = health;
  29. }else {
  30. System.out.println("健康值赋值不合理,将使用默认值60");
  31. this.health = 60;
  32. }
  33. }
  34. public void setName(String name) {
  35. this.name = name;
  36. }
  37. public String getName() {
  38. return name;
  39. }
  40. public void setSex(String sex) {
  41. if(sex.equals("雌") || sex.equals("雄")) {
  42. this.sex = sex;
  43. }else {
  44. System.out.println("性别不合适,使用默认性别雌性");
  45. this.sex = "雌";
  46. }
  47. }
  48. public String getSex() {
  49. return sex;
  50. }
  51. }

2. 访问权限修饰符

image.png
image.png

2.1 类的访问权限修饰符

1.public 本项目中任何位置都可以访问 2.默认不写 本包中可以访问

2.2 类成员的访问权限修饰符

1.private 表示私有的本类中可以访问 2.默认不写的 本包中可以访问 3.protected 受保护的 本类中 本包中 子类中 4.public 本项目中任何位置都可以访问

  1. package com.qfedu.test2;
  2. /**
  3. * 类的访问修饰符:
  4. * 1.public 本项目中任何位置都可以访问
  5. * 2.默认不写 本包中可以访问
  6. *
  7. * 类成员(属性和方法)的访问修饰符:
  8. * 1.private 表示私有的本类中可以访问
  9. * 2.默认不写的 本包中可以访问
  10. * 3.protected 受保护的 本类中 本包中 子类中
  11. * 4.public 本项目中任何位置都可以访问
  12. * @author WHD
  13. *
  14. */
  15. public class Note {
  16. private String field1;
  17. String field2;
  18. protected String field3;
  19. public String field4;
  20. private void m1() {}
  21. void m2() {}
  22. protected void m3() {}
  23. public void m4() {}
  24. public static void main(String[] args) {
  25. A a = new A(); // 同类中
  26. Note note = new Note();
  27. System.out.println(note.field1); // 红色方框 私有
  28. System.out.println(note.field2); // 蓝色三角 包级别
  29. System.out.println(note.field3); // 黄色菱形 受保护的 本类 本包 子类
  30. System.out.println(note.field4); // 绿色原点 最大范围 public
  31. note.m1();
  32. note.m2();
  33. note.m3();
  34. note.m4();
  35. }
  36. }
  37. class A{
  38. }
  1. package com.qfedu.test2;
  2. public class Test {
  3. public static void main(String[] args) {
  4. A a = new A(); // 同包中 可以访问
  5. // 访问属性
  6. Note note = new Note();
  7. System.out.println(note.field2);
  8. System.out.println(note.field3);
  9. System.out.println(note.field4);
  10. note.m2();
  11. note.m3();
  12. note.m4();
  13. }
  14. }
  1. package com.qfedu.test3;
  2. import com.qfedu.test2.Note;
  3. /**
  4. * 属性访问和类访问
  5. * @author WHD
  6. *
  7. */
  8. public class Test {
  9. public static void main(String[] args) {
  10. // A a = new A(); 因为A是包级别的访问权限 所以不同包不能访问
  11. Note note = new Note();
  12. System.out.println(note.field4);
  13. note.m4();
  14. }
  15. }

3. static关键字

3.1 static适用场景

static可以用来修饰
成员变量
静态变量,可以直接通过类名访问

成员方法
静态方法,可以直接通过类名访问

代码块
静态代码块,当Java虚拟机加载类时,就会执行该代码块

3.2 static修饰变量

被static修饰的变量在内存中只有一个拷贝,可以用于数据共享,实现多个实例之间的数据传递

类内部,可在任何方法内直接访问静态变量

其他类中,可以直接通过类名访问

  1. package com.qfedu.test4;
  2. /**
  3. * 接水
  4. * @author WHD
  5. *
  6. */
  7. public class Person {
  8. static int capacity = 10000; // 容量 1000毫升水
  9. String name; // 名字
  10. public void getWater() {
  11. if(capacity > 0) {
  12. capacity -= 200;
  13. System.out.println(name + "接水200毫升,还剩下" + capacity + "毫升");
  14. }else {
  15. System.out.println("没水了,请换水");
  16. }
  17. }
  18. }
  1. package com.qfedu.test4;
  2. public class TestPerson {
  3. public static void main(String[] args) {
  4. Person zhaosi = new Person();
  5. zhaosi.name = "赵四";
  6. zhaosi.getWater();
  7. Person guangkun = new Person();
  8. guangkun.name = "广坤";
  9. guangkun.getWater();
  10. Person xiaobao = new Person();
  11. xiaobao.name = "小宝";
  12. xiaobao.getWater();
  13. // 问题2:我们发现不能按照设想将水容量这个数据共享
  14. // 因为capacity是实例变量 每new一个对象在内存中就 存在一份
  15. // 所以我们new三个对象 内存中有三个capacity 值都为1000
  16. }
  17. }
  1. package com.qfedu.test5;
  2. /**
  3. * 选民类
  4. * 选民名称
  5. * 总票数
  6. * @author WHD
  7. *
  8. */
  9. public class Voter {
  10. static int ticketCount = 100;
  11. String name;
  12. public boolean voteFor() {
  13. if(ticketCount > 0) {
  14. ticketCount --;
  15. System.out.println(name + "投了一票,还剩余" + ticketCount);
  16. return true;
  17. }else {
  18. System.out.println("投票完毕请等待 下一届");
  19. return false;
  20. }
  21. }
  22. public static void main(String[] args) {
  23. Voter v1 = new Voter();
  24. v1.name = "赵四";
  25. v1.voteFor();
  26. Voter v2 = new Voter();
  27. v2.name = "大拿";
  28. v2.voteFor();
  29. Voter v3 = new Voter();
  30. v3.name = "小宝";
  31. v3.voteFor();
  32. for (int i = 1; i < 120; i++) {
  33. Voter v = new Voter();
  34. v.name = i + "号选民";
  35. if(!v.voteFor()) {
  36. break;
  37. }
  38. }
  39. }
  40. }

3.3 static修饰方法

静态方法:可直接通过类名访问

静态方法中不能使用this和super

不能直接访问所属类的实例变量和实例方法

可直接访问类的静态变量和静态方法

实例方法:通过实例访问

可直接访问所属类的静态变量、静态方法、实例变量和实例方法

静态方法必须被实现

  1. package com.qfedu.test5;
  2. /**
  3. * 1.静态与静态直接调用
  4. * 2.静态访问非静态 必须先new对象
  5. * 3.非静态的访问静态的 直接调用
  6. * @author WHD
  7. *
  8. */
  9. public class TestStaticMethod {
  10. public void m3() {
  11. m1();
  12. }
  13. public void m1() {
  14. m2(); // 直接调用 因为实例方法m1可以调用的时候 类一定被加载过了
  15. // 静态方法已经初始化过了
  16. System.out.println("普通方法m1");
  17. }
  18. public static void m2() {
  19. // m1(); 不能直接调用m1 必须先new对象
  20. // 因为m2方法初始化的时候 m1方法不一定存在(必须依赖对象而存在)
  21. System.out.println("静态方法m2");
  22. }
  23. public static void main(String[] args) {
  24. TestStaticMethod.m2();
  25. TestStaticMethod tsm = new TestStaticMethod();
  26. tsm.m1();
  27. }
  28. }
  1. package com.qfedu.test5;
  2. public class Test1 {
  3. public static void main(String[] args) {
  4. TestStaticMethod tsm = new TestStaticMethod();
  5. tsm.m1();
  6. TestStaticMethod.m2();
  7. tsm.m3();
  8. }
  9. }

3.4 static修饰代码块

静态代码块

随着类被加载执行 多个静态代码块按照书写顺序执行 每个只执行一次 因为类只加载一次

静态代码块用于实现一些前置的操作 比如数据初始化 等

普通代码块 每new一次对象 执行一次

  1. package com.qfedu.test5;
  2. /**
  3. * 静态代码块
  4. * 随着类被加载执行 多个静态代码块按照书写顺序执行 每个只执行一次 因为类只加载一次
  5. *
  6. * 静态代码块用于实现一些前置的操作 比如数据初始化 等
  7. * @author WHD
  8. *
  9. */
  10. public class TestStaticCode {
  11. static int num = 10;
  12. static {
  13. System.out.println("静态代码块1");
  14. }
  15. static {
  16. System.out.println("静态代码块2");
  17. }
  18. {
  19. System.out.println("实例代码块1");
  20. }
  21. {
  22. System.out.println("实例代码块2");
  23. }
  24. public static void main(String[] args) {
  25. System.out.println(num);
  26. TestStaticCode tsc1 = new TestStaticCode();
  27. TestStaticCode tsc2 = new TestStaticCode();
  28. TestStaticCode tsc3 = new TestStaticCode();
  29. }
  30. }

3.5 访问规则

1.静态与静态直接调用 2.静态访问非静态 必须先new对象 3.非静态的访问静态的 直接调用

4. 类加载的过程

4.1 名词解释

方法区:是JDK提供的一个规范,符合这个规范即可称之为方法区 元空间:方法区的实现,JDK1.8叫元空间,用来加载类信息文件,初始化静态相关信息等 永久代:JDK1.7 之前叫永久代,方法区的实现

4.2 加载过程

1.当我们第一次访问一个类时,JVM先在方法区查看是否有加载当前类信息文件 如果有,在堆中开辟空间,将栈中的引用指向堆中的空间 如果没有,先加载类信息文件,然后在堆中开辟空间,将栈中的引用指向堆中的空间