目录
一.面向对象三大特性
二.封装
三.继承
3.1 单级继承
3.2 多级继承
3.3 不可继承
3.4 权限
3.5 重写
3.6 super
封装 继承 多态(这玩意下次讲)
//面向对象案例:车子的发动 //分析: 类: 车类 对象: new 属性:颜色,品牌等 方法:启动 //问题: 价格可以赋值为负数--程序逻辑没问题,但数据不合理 //解决方案:在程序中对属性的值进行判断是否大于0,如果小于0,则给定一个默认值即可 //封装性:不要使用属性直接赋值与取值,而是通过方法进行封装;该方法就是set/get方法 //好处:提高安全性及复用性 //封装性操作步骤: //1.编写set/get方法 //2.属性私有化 class Car{ private String brand; //写上set和get private:私有权限,限制属性只能在当前类中使用 private int price; /*public void start() { System.out.println(brand+"品牌的汽车正在发动;价格为:"+price); }*/ //set规范写法:set+属性名首字母大写,参数名与属性名一致 public void setPrice(int price) { //注意:此处是为了说明封装特性,才进行的逻辑判断;后续没有特殊说明,则直接赋值 if(price<0) { this.price = 100000; //给定异常数据的默认值 }else { this.price = price; } } //get规范写法: get+属性名首字母大写 public int getPrice() { return price; //可以+this吗? 可以,只是get方法中没有冲突则可省略 } public void setBrand(String brand) { this.brand = brand; } public String getBrand() { return brand; } } public class Test { public static void main(String[] args) { Car car = new Car(); car.setBrand("红旗"); car.setPrice(-1000); System.out.println("---------"); //car.price = -10000; //加权限限制--从源头上规避异常数据的录入 car.setPrice(-10000); System.out.println(car.getPrice()+"==>"+car.getBrand()); //取值 } }
生活中的继承:施舍方的赠与,接受方的获取
程序中的继承:两个类之间满足“is a”的关系,这样的两个类,我们可以设置为继承
特点:有了继承关系,子类拥有父类的属性和方法
父类的选择:
在生活中满足is a关系的类很多,我们需要从中选择最合适的父类
例如: 狗类是动物类,也是生物类,也是物质类
直接父类选择动物类---特征和行为最接近
结论: 重合点越多,越接近直接父类
重合点越少,越接近Object类(祖宗类)
继承的应用:
案例: 子类有狗类,鸟类,找出他们的特征和行为
狗类:
特征: [品种,姓名,年龄],毛色
行为: [吃,睡],跑
鱼类: [品种,姓名,年龄]
特征: [吃,睡],游
父类:动物类--共性抽取,将所有类共有的特征和行为放入父类,子类只需继承即可
特征: 品种,姓名,年龄
行为: 吃,睡
作用:简化代码量,提高复用性
public class Animal { String brand; String name; int age; public void eat() { System.out.println(name+"正在吃"); } public void sleep() { System.out.println(name+"正在睡"); } } //Dog类继承Animal类 class Dog extends Animal{ String color; public void run() { System.out.println(name+"正在跑.."); } } //Fish类继承Animal类 class Fish extends Animal{ public void swim() { System.out.println(name+"正在游..."); } } public class Test { public static void main(String[] args) { Dog dog = new Dog(); //实例化子类对象 dog.name = "旺财"; //调用父类的特征 dog.color = "黄色"; //调本类的特征 dog.eat(); //调父类的行为 dog.run(); //调本类的行为 //匿名对象:没有名字的对象,只操作一次时,可直接new对象(匿名对象)调方法 //new Animal().run(); //注意:父类不能调子类的特征和行为 } }
//细节: //不能多继承(多个父亲),但是可以多级继承(有父类,爷爷类,太爷爷类...) //多级继承的特征和行为都可以叠加 //案例: //爷爷拥有100万,父亲拥有一辆宝马车,儿子拥有一个奥特曼 class GrandFather{ public void haveMoney() { System.out.println("拥有100万"); } } class Father extends GrandFather{ //Son间接继承GrandFather public void haveCar() { System.out.println("拥有宝马车"); } } class Son extends Father{ //Son直接继承Father public void havePeron() { System.out.println("拥有奥特曼"); } } public class Test { public static void main(String[] args) { Son son = new Son(); son.havePeron(); //调子类自身方法 son.haveCar(); //调父类方法 son.haveMoney(); //调间接父类方法 } }
1. 父类私有的特征和行为不能被继承
2. 构造方法不能被继承
3. 在不同场景下的有些权限限制的特征和行为不能被继承(测试说明)
//不能被继承情况: //1. 父类私有的特征和行为不能被继承 //2. 构造方法不能被继承-----最好测试带参构造 public class Person { private String name; //私有属性 public Person() {} public Person(String name) { } } class Student extends Person{ public void study() { //System.out.println(name); //私有权限,在子类中不能继承 } } public class Test { public static void main(String[] args) { //父类有带参构造,子类没有,通过子类调父类带参构造,会报错;说明构造方法没有继承性 //Student st = new Student("666"); } }
在java的面向对象案例中,主要权限有:private,default,protected,public
本类 | 同包 | 非同包子类 | 其他 | |
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
//案例:父亲和儿子吃饭的方式不同 //概述: 子类的方法和父类完全一致(返回值类型,方法名,参数类型) //子类的权限不小于父类(一般都为public) //应用场景:当父类的方法不满足子类时,子类可重写父类方法 class Father{ public void eat() { System.out.println("非常绅士的吃..."); } } class Son extends Father{ @Override //重写注解,标记下面的方法是重写方法,如果不是则报错 public void eat() { System.out.println("狼吞虎咽的吃..."); } } public class Test { public static void main(String[] args) { Son son = new Son(); son.eat(); } }
this:当前对象
this.属性
this.方法
this调构造方法:this() this(参数)
super:父类对象
super.属性: 调父类对象的属性
super.方法: 调父类对象的方法
super()或super(参数): 调父类的构造方法
注意:在继承关系中,this如果自身没有属性和方法,根据继承性会调用父类的
//=========================super调方法======================== class Son extends Father{ /* public void haveMoney() { System.out.println("拥有100块"); }*/ public void have() { System.out.println("拥有奥特曼"); //super.haveMoney(); //调用父类的方法 this.haveMoney(); //调自身的方法 } } public class SuperMethod { public static void main(String[] args) { new Son().have(); } } //=========================super调属性======================== class Fu{ String name="凤姐"; } class Zi extends Fu{ String name = "刘亦菲"; public void test(){ System.out.println(super.name); //调用父类的属性 System.out.println(this.name); //自己有属性,调自己的,没有才调父类的 System.out.println(name); //相当于this.name } } public class SuperField { public static void main(String[] args) { Zi zi = new Zi(); zi.test(); } } //=========================super调构造方法======================== //子类实例化过程: //案例:C继承B,B继承A,实例化C的对象,查看实例化过程 //分析:当调用子类构造方法时,在构造方法中,默认会有super()放在首句;表示先调父类无参构造; //所以最终先打印父类的无参构造,再打印子类构造 //继承中,子类实例化,为何会默认调super()? 因为需要将父类资源先加载;子类才能拥有父类资源 class A /*extends Object*/{ //没有继承的父类,则直接继承Object public A() { super(); //---调Object的无参构造 System.out.println("A的无参构造"); } } class B extends A{ public B() { super(); System.out.println("B的无参构造"); } } class C extends B{ public C() { super(); System.out.println("C的无参构造"); } } public class SuperTest1 { public static void main(String[] args) { C c = new C(); } }
(所以有人想继承我的bug吗?=-=! 没有我接着写bug去了...)