一、封装:
封装的介绍:
-
定义:封装就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,出现的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。
-
优点:
- 可以隐藏实现细节:方法(连接数据库)<--调用(传入参数..);
- 可以对数据进行验证,保证安全合理
-
实现步骤:
-
将属性进行私有 private【不能直接修改属性】;
-
提供一个公共的set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){ //加入数据验证的业务逻辑 属性 = 参数名 }
-
提供一个公共的get方法,用于获取属性值;
public XX getXxx(){ // 权限判断 return xxx; }
-
-
举例:做一个小程序,不能随便查看别人的年龄,工资等隐私,并对设置年龄进行合理的验证,年龄合理就设置,否则就默认,年龄必须在1-120之间,工资不能直接查看,姓名的长度在2-6之间:
class Person{ public String name; // 名字 公开 private int age; // 年龄 私有化 private double salary; // 工资 私有化 // 设置 名字 public void setName(String name) { if(name.length() >= 2 && name.length() <= 6) { this.name = name; }else{ System.out.println("名字的长度不对,需要(2-6)个字符,默认名字"); this.name = "无名人"; } } // 获取 姓名 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 = " + name + " age = " + age + " salary = " + salary; } } //然后我们在main主函数里面进行创建对象 public class Encapsulation { public static void main(String[] args) { /* * 练习:请大家看一个小程序,不能随便查看别人的年龄,工资等隐私,并对设置的年龄进行 * 合理的验证,年龄合理就设置,否则就默认,年龄必须在1-120之间工资不能直接查看,name * 的长度在2-6之间。 * */ Person person = new Person(); person.setName("Jack"); person.setAge(30); person.setSalary(30000); System.out.println("----Jack的信息-----------"); System.out.println(person.info()); } }使用构造器指定属性:
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; // 在构造器中进行值的校验 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 = "无名人"; } } // 获取 姓名 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 = " + name + " age = " + age + " salary = " + salary; } } // 此时main中就可以这么创建对象 // 使用构造器指定属性 Person smith = new Person("smith", 2000, 50000); System.out.println("----smith的信息-----------"); System.out.println(smith.info());
二、继承:
-
我们先来看一段代码:
// 大学生-> 模拟大学生考试情况 public class Graduate { public String name; public int age; private double score; public void setScore(double score) { this.score = score; } public void testing(){ // 和 Pupil 不一样 System.out.println("大学生 " + name + "正在考高数.."); } public void showInfo() { System.out.println("姓名:"+ name + " 年龄:" + age + " 分数:" + score); } }// 小学生-> 模拟小学生考试情况 public class Pupil { public String name; public int age; private double score; public void setScore(double score) { this.score = score; } public void testing(){ System.out.println("小学生 " + name + "正在考小学数学.."); } public void showInfo() { System.out.println("姓名:"+ name + " 年龄:" + age + " 分数:" + score); } } -
上面我们编写了两个类,一个是Pupil类,一个是Graduate类。但是我们发现 两个类的属性(name, age, score)和方法(testing,showInfo) 有很多相同之处,怎么办呢? 这时候我们就可以用继承(代码的复用性)来很好的解决这个问题。
-
继承的介绍:
-
继承:继承可以解决代码服复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。
-
继承语法:
class 子类 extends 父类 { }- 子类就会自动拥有父类的属性和方法;
- 父类又叫超类、基类;
- 子类又叫派生类;
-
继承的细节:
- 子类继承了所有的属性和方法,非私有属性的方法可以直接访问,但是私有属性或方法不能再子类中直接访问,要通过公共的方法去访问呢;
- 子类必须调用父类的构造器,完成父类的初始化;
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中
super()去指定使用父类的那个构造器完成对父类的初始化工作,否则,编译不会通过; - super 在使用时,必须放在构造器的第一行(super只能在构造器中使用);
- super() 和 this() 都只能在构造器的第一行,因此这两个方法不能共存一个构造器;
- 子类最多只能继承一个父类(指直接继承),即java中是单继承继承。思考【如何让A类继承B类和C类?.... A 继承 > B 继承 > C 继承】;
- 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系;
案例:
-
此时我们再来看之间大学生与小学生的问题:
-
首先我们给创建一个
Student的基类,将 Pulic 和Graduate 类中相同的属性和方法提取出来:// Student.class // 父类,是Pupil 和 Graduate 类的父类 public class Student { public String name; public int age; private double score; public void setScore(double score) { this.score = score; } public void showInfo() { System.out.println("姓名:"+ name + " 年龄:" + age + " 分数:" + score); } } -
创建
Pulic类继承Student类:public class Pupil extends Student { // 小学生 public void testing(){ // 和 Pupil 不一样 System.out.println("小学生" + name + "正在考数学.."); } } -
创建
Graduate类继承Student类:public class Graduate extends Student{ // 大学生 public void testing(){ // 和 Pupil 不一样 System.out.println("小学生" + name + "正在考高数.."); } } -
在
main主函数中创建这两个对象:public static void main(String[] args) { Pupil pupil = new Pupil(); pupil.name = "小明~"; pupil.age = 6; pupil.testing(); pupil.setScore(66); pupil.showInfo(); System.out.println("----------------"); Graduate graduate = new Graduate(); graduate.name = "大明~"; graduate.age = 6; graduate.testing(); graduate.setScore(99); graduate.showInfo(); // 运行结果: // 小学生小明~正在考数学.. // 姓名:小明~ 年龄:6 分数:66.0 // ---------------- // 小学生大明~正在考高数.. // 姓名:大明~ 年龄:6 分数:99.0 }
-
-
三、多态:
- 首先看一个主人喂食的故事:
问题:当主人有不同的食物,需要给不同的动物喂食,这就需要在父类中写许多重载的方法:cat -> fish、 dog -> bone、 pig - rice...
传统的方法带来的问题是:代码的复用性不高,而且不利于维护,因此我们需要 多态 来解决问题。
-
多态的介绍:
-
多态:方法或对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承的基础之上的;
-
多态的具体体现:
-
方法的多态:重写和重载就体现多态;
-
对象的多态(重点,难点):
-
一个对象的编译类型和运行类型可以不一致;
-
编译类型在定义对象时,就确定,不能改变;
-
运行类型是可以变化的;
-
编译类型看定义时 = 号的 左边,运行类型看 = 号的 右边;
-
案列:
Animal animal = new Dog(); //【animal 编译类型时Animal,运行类型Dog】 animal = new Cat(); //【animal 的运行类型变成了cat,编译类型任然是 Animal】
-
-
-
-
此时我们以 多态 来看之间主人喂食的这个程序:
-
创建一个Master类:
class Master { private String name; public Master(String name) { this.name = name; } // public void feed(Dog dog, Bone bone) { // System.out.println(name + "给" + dog.getName() + "吃" + bone.getName()); // } // // public void feed(Cat cat, Fish fish) { // System.out.println(name + "给" + cat.getName() + "吃" + fish.getName()); // } // 上面代码 复用性差,不利于扩展和维护, 我们可以使用多态 public void feed(Animal animal, Food food) { System.out.println(name + "给" + animal.getName() + "吃" + food.getName()); } public String getName() { return name; } public void setName(String name) { this.name = name; } } -
分别创建Food,Fish,Bone,Animal,Dog,Cat类:
class Food { private String name; public Food(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Fish extends Food { public Fish(String name) { super(name); } } class Bone extends Food{ public Bone(String name) { super(name); } } class Animal { private String name; public Animal(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Dog extends Animal { public Dog(String name) { super(name); } } class Cat extends Animal { public Cat(String name) { super(name); } } -
上Master类中feed方法,我们使用多态将解决了之前的繁琐,不利于维护的问题。我们可以在main方法创建并调用这个方法,看一下运行结果:
public static void main(String[] args) { Master tom = new Master("汤姆"); Dog dog = new Dog("小白狗"); Bone bone = new Bone("大棒骨"); Cat cat = new Cat("小黄猫"); Fish fish = new Fish("黄丽鱼"); tom.feed(dog, bone); tom.feed(cat, fish); }
-