一、封装
1 为什么要封装?
封装的基本的定义,就是隐藏实现,公开接口
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
实例:
public class Enapsulation {
//封装属性
private String name;
private int age;
//构造器
public Enapsulation(String name, int age) {
this.name = name;
this.age = age;
}
//设置接口
public String getName() {
return name;
}
public void setName(String name) {
//这里可对传入的数据进行验证,相当于业务逻辑
if (name.length() >= 2 && name.length() <=6) {
this.name = name;
}else{
System.out.println("名字长度不正确");
this.name = "无名人";
}
}
public int getAge() {
//这里可以加入if判断 对数据进行加密,如权限不够,不给查看
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say(){
return "\t姓名 " + name + "\t年龄 " + age;
}
}
- 封装的优点
-
1. 良好的封装能够减少耦合,避免牵一发而动全身
-
2. 类内部的结构可以自由修改。
-
3. 可以对成员变量进行更精确的控制。
-
4. 隐藏信息,实现细节。
二、继承
1 为什么要继承?
通过实例来说明这个需求。
开发动物类,其中动物分别为企鹅以及老鼠,要求如下:
- 企鹅:属性(姓名,id),方法(吃,睡,自我介绍)
- 老鼠:属性(姓名,id),方法(吃,睡,自我介绍)
//企鹅类
public class Penguin {
private String name;
private int id;
public Penguin(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
//老鼠类
public class Mouse {
private String name;
private int id;
public Mouse(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个
父类
public class Animal {
private String name;
private int id;
public Animal(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
这个Animal类就可以作为一个父类,然后企鹅类和老鼠类继承这个类之后,就具有父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性(复用性主要是可以多次使用,不用再多次写同样的代码) 继承之后的代码:
//企鹅类:
public class Penguin extends Animal {
public Penguin(String myName, int myid) {
super(myName, myid);
}
}
//老鼠类:
public class Mouse extends Animal {
public Mouse(String myName, int myid) {
//super 调用父类方法
super(myName, myid);
}
}
2 继承的格式
继承的特性
-
子类拥有父类非 private 的属性、方法,private的成员用方法get()访问。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。(重写)
-
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
-
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
class gradfather{
String name = "grad";
String hobby = "guapi";
int age = 48;
}
class father extends gradfather{
String name = "father";
//因为是private属性,所以子类无法访问,
//虽然父类有public age 但是,无法访问,age在这里就结束了
private int age = 28;
//可以通过 getage()方法访问private属性age
public int getAge() {
return age;
}
}
class son extends father{ String name = "son"; }
- 子类必须调用父类的构造器,完成父类的初始化
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指.定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
class A{
public A(){
System.out.println("a");
}
public A(String name){
System.out.println("a name");
}
}
class B extends A{
public B(){
this("abc");
System.out.println("b");
}
public B(String name){
super();//默认存在
System.out.println("b name");
}
}
- 继承的内存布局
- super和this的比较
三、多态
1 什么是多态?
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
重写和重载的区别:
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
//或者((Cat)a).work()
Cat c = (Cat)a; //把a的运行类型从Animal转为Cat
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
实例 思考:
体会动态绑定机制
public class DynamicBinding {
public static void main(String[] args) {
father a = new son(); //编译类型是father ,运行类型是son
System.out.println(a.sum());
System.out.println(a.sum1());
}
}
class father {
public int i = 10;
public int sum(){
//情况一:giti()方法触发动态绑定机制,因为a的运行类型是son,所以这里调用子类son的geti()方法
return geti() + 10; //20 + 10
}
public int sum1(){
//情况二:属性没哟动态绑定机制,哪里申明哪里使用,返回当前类的值
return i + 10; //即 10 +10
}
public int geti(){
return i;
}
}
class son extends father{
public int i = 20;
//情况一:假如注销此sum()方法,则会去调用父类的sum()方法,
public int sum(){
return i + 20;
}
//情况二:假如注销此sum1()方法,则会去调用父类的sum1()方法
public int sum1(){
return i + 10 ;
}
public int geti(){
return i ;//属性没有动态绑定机制,返回当前类的值 20
}
}
多态的实现方式
方式一:重写
方式二:接口
-
1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
-
2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。