封装,继承
- 封装:就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。
- 封装实现三步骤
- 将属性进行私有化private【不能直接修改属性】
- 提供一个公共set方法,用于对属性判断并赋值。
- 提供一个公共的get方法,用于获取属性的值。
- 案例
package com.hspedu.encap; //案例:不能随变查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证 //年龄合理就设置,否则给默认年龄必须1-120之间 //年龄工资不能直接查看,name的长度在2-6字符之间 public class Encapsulation01 { public static void main(String[] args) { Person person = new Person(); //person.setName("贾树行"); person.name = "李四";//这个属性是公开的可以直接修改 person.setAge(20); person.setSalary(30000); //构造器 Person smith = new Person("smith", 2000, 30000); System.out.println("====smith的信息===="); System.out.println(smith.info()); System.out.println(person.info());//信息为:名字李四 age20 薪水30000.0 } } class Person { public String name;//名字公开 private int age;//私有化 private double salary; //构造器 alt+insert public Person() { } public Person(String name, int age, double salary) { //这样的话之前的校验就被破解无用了 // this.name = name; // this.age = age; // this.salary = salary; //我们可以将set方法写在构造器中,这样仍然可以验证 setName(name);// setAge(age); setSalary(salary); } public void setName(String name) { //加入对数据的校验 if (name.length() >= 2 && name.length() <= 6) { this.name = name; } else { System.out.println("名字的长度不对需要(2-6)个字符,给了一个默认名字张三。"); this.name = "张三"; } } //自己写set,get太慢快捷键 public String getName() { return name; } public int getAge() { return age; } public void setAge(int age) { if (age >= 1 && age <= 120) { this.age = age; } else { System.out.println("年龄需要在1-120之间,给默认年龄18"); this.age = 18;//给一个默认年龄 } } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String info() { return "信息为:名字" + name + " age" + age + " 薪水" + salary; } }
-
继承:解决代码复用性
-
继承可以解决代码复用,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可
-
语法:class 子类 extends 父类{ }
-
子类就会自动拥有父类定义的属性和方法
-
-
继承细节
-
子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
-
在用子类new个对象时,new Person():子类无参构造器被调用,必须调用父类的构造器,完成父类初始化(为什么父类构造器也被调用呢?):因为在子类默认无参构造器中的第一行语句有一个隐藏的命令,super();//默认调用父类的无参构造器,其实父类的无参构造器第一行也隐藏一个super。super是在构造器中的
-
当创建子类对象时,不管使用子类的那个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。(super(12,"jiashuhang"))指定调用有参构造器
-
如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表)
-
super在使用时,必须放在构造器第一行(super只能在构造器中使用)
-
super()和this()都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器。
-
java所有类都是Object类的子类,Object是所有类的基类
-
父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)
-
子类最多只能继承一个父类(指直接继承),即java中是单继承机制。(思考如何放A类继承B类和C类):A继承B,B在继承C,中转一下就可
-
不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。(Person is a Music?)集成之间要有因果关心,(Dog is a animal)。
-
- 继承的本质
- 内存中发生了什么
-
package com.hspedu.extend_; public class ExtendsTheory { public static void main(String[] args) { Son son = new Son();//内存的布局 //这时注意,要按照查找关系来返回信息 //1.首先看子类是否有该属性 //2.如果子类有这个属性,并且可以访问,则返回信息 //3.如果子类没有这个属性,就看父类有没有这个属性, //(如果父类有该属性,并且可以访问,就返回信息) //4.如果父类没有就按照3.的规则,继续找上级,知道Object... System.out.println(son.name);//返回的就是大头儿子 //System.out.println(son.getName());//返回的就是大头儿子 System.out.println(son.age);//37 System.out.println(son.hobby);//旅游 } } class GrandPa{ String name = "大头爷爷"; String hobby = "旅游"; } class Father extends GrandPa{ String name = "大头爸爸"; int age = 37;//private,如果把这个设置为私有的属性 //那么通过son这个对象是访问不到age属性的 //因为private只能在本类访问,new Father(). } class Son extends Father{//子类 String name = "大头 儿子"; //私有的属性就用get方法访问ok // public String getName() { // return name; // } }
- 内存中发生了什么