Java入门第四节
一.继承
问题:
隔壁的王阿姨养了一只猫和一只仓鼠,也想使用这个app,应该这么办
解决:
1.找出所有动物的共性(如.有名字,品种,年龄,吃饭,跑等等),创建一个共性类,为宠物类
package com.microsoft.bean;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Animal {
// 所在的小区
private static String plot = "希望小区";
// 名字
private String name;
// 种类
private String variety;
// 年龄
private int age;
// 食物
private String food;
// 方法的重写
public void setName(String name) {
if (name.length() < 20) {
this.name = name;
}else {
System.out.println("你的宠物名字过长");
}
}
public void setAge(int age) {
if (age > 0 && age <30){
this.age = age;
}else {
System.out.println("你的宠物年龄错误");
}
}
public static String getPlotInstance(){
return plot;
}
// 无参数构造函数(无参构造器)
public Animal() {
}
// 有参数的构造函数(有参构造)
public Animal(String name, String variety, int age, String food) {
this.name = name;
this.variety = variety;
this.age = age;
this.food = food;
}
// 我们要给所以宠物打疫苗
public static void injection(){
System.out.println("所以的宠物,月底打疫苗");
}
// 宠物的行为
public void eat() {
System.out.println(this.name+"吃饭");
}
public void sleep() {
System.out.println(this.name+"睡觉");
}
public void run() {
System.out.println(this.name+"正在奔跑");
}
}
2.创建猫类与仓鼠类,但是有发现了一个问题,我们不能把Dogs里的代码每个都写一遍吧,这样非常麻烦,所有我们要引入继承的概念;
继承:儿子继承了父亲的一些特性
(1).关键字extends的意思是“扩展”,子类是父类的扩展;
(2).Java中的类只有单继承,没有多继承;(一个儿子只有一个父亲,但是一个父亲可以有多个儿子)
(3).继承只能继承一些特性,有些特性是无法被继承
一.构造器(Constructor):子类不能继承父类的构造器,但可以通过super关键字调用父类的构造器。
二.final成员变量和方法:final修饰的成员变量和方法是不可修改的,无法被子类继承或覆盖。
需要注意的是,虽然接口(Interface)也可以被看作一种继承关系,但接口之间无法直接进行继承。一个类可以实现多个接口,但只能继承一个父类。
看不懂的,后面会讲
3. 使用继承
public class Hamster extends Animal{
}
public class Dogs extends Animal {
}
public class Cat extends Animal{
}
import com.microsoft.bean.Cat;
import com.microsoft.bean.Dogs;
import com.microsoft.bean.Earth;
import com.microsoft.bean.Hamster;
public class Application {
public static void main(String[] args) {
// 张大爷,注册APP,使用new实例化
Dogs zhangDog = new Dogs();
// 张大爷设置狗的状态
zhangDog.setName("阿黄");
zhangDog.setVariety("中华田园犬");
zhangDog.setAge(10);
zhangDog.setFood("剩菜剩饭");
System.out.println("张大爷家狗的信息:" +zhangDog);
// 王阿姨,注册APP
Cat wangCat = new Cat();
Hamster wangHamster = new Hamster();
// 王阿姨设置猫的状态
wangCat.setName("大橘");
wangCat.setVariety("橘猫");
wangCat.setAge(3);
wangCat.setFood("小鱼干");
// 王阿姨设置仓鼠的状态
wangHamster.setName("小白");
wangHamster.setVariety("不知道");
wangHamster.setAge(1);
wangHamster.setFood("白菜");
System.out.println("王阿姨家猫的信息:" +wangCat);
System.out.println("王阿姨家仓鼠的信息:" +wangHamster);
}
}
二.多层继承
1.像灰太狼家族,一层一层的继承,爷爷传承到爸爸、爸爸传承到孙子;
2.一个类不能直接继承多个类,java是单继承语言,不支持多继承;
3.不能写成 class A extends B,C;
4.但可以实现继承多个类 class A extends B,class C extends A 这样C就同时继承了B和A两个类了;
如.狗继承宠物,拉布拉多继承狗
public class Dogs extends Animal{
}
public class Labrador extends Dogs {
}
三.Object
可以有Ctrl+h查看继承关系:
从这里可以看出:它的父类是Object
Java Object 类 | 菜鸟教程 (runoob.com)
Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承 Object,成为 Object 的子类。
Object 类可以显式继承,也可以隐式继承,以下两种方式是一样的:
// 显式继承:
public class Runoob extends Object{
}
// 隐式继承:
public class Runoob {
}
Object的方法有:Java-Objec-CSDN博客
四.方法重写
由于动物会叫所以我们要在宠物类中添加动物叫方法
public void breaking() {
System.out.println("宠物叫");
}
出现问题王阿姨家的猫的叫声很奇怪,如何解决。
使用方法的重写(父类的功能,子类不一定需要,或者不一定满足):
1.重写需要有继承关系,子类重写父类的方法;
2.方法名与参数必须相同;
3.修饰词:范围可以扩大但不能缩小(修饰词:public > protected > default > private)
4.抛出异常:范围,可以被缩小,但不能被扩大 (Exception > ClassNotfoundException)
3与4后面会讲,看不懂跳过
使用:
package com.microsoft.bean;
public class Cat extends Animal{
@Override
public void breaking() {
System.out.println("喵喵~~~~~");
}
}
补充:
1.当我们使用外部库中的方法时,可以通过继承关系来重写(覆盖)该方法。
2.在Java中,静态方法是与类关联的方法,而不是与实例对象关联的方法。因为静态方法与类直接绑定,不依赖于对象的创建,所以无法被子类重写。父类中的静态方法只能被隐藏,而不能被子类中的同名静态方法所重写。你可以通过在子类中定义一个与父类静态方法同名的静态方法来隐藏父类中的静态方法。
五.super
问题:由于子类不能继承父类的构造器,用户想要注册时初始化怎么办;
解决:我们使用前面教的快捷键,在每个子类上重新生成构造器;
package com.microsoft.bean;
public class Hamster extends Animal{
@Override
public void breaking() {
System.out.println("仓鼠叫");
}
public Hamster() {
}
public Hamster(String name, String variety, int age, String food) {
super(name, variety, age, food);
}
}
package com.microsoft.bean;
public class Dogs extends Animal {
@Override
public void breaking() {
System.out.println("汪汪~~~~~");
}
public Dogs() {
}
public Dogs(String name, String variety, int age, String food) {
super(name, variety, age, food);
}
}
package com.microsoft.bean;
public class Cat extends Animal{
@Override
public void breaking() {
System.out.println("喵喵~~~~~");
}
public Cat() {
}
public Cat(String name, String variety, int age, String food) {
super(name, variety, age, food);
}
}
如果你仔细观察会子类的构造方法与父类不一样,子类的构造方法中有关键字super,super关键字可以让子类调用父类的构造器。
效果:
import com.microsoft.bean.Cat;
import com.microsoft.bean.Dogs;
import com.microsoft.bean.Earth;
import com.microsoft.bean.Hamster;
public class Application {
public static void main(String[] args) {
// 张大爷,注册APP,使用new实例化
Dogs zhangDog = new Dogs("阿黄","中华田园犬",10,"剩菜剩饭");
System.out.println("张大爷家狗的信息:" +zhangDog);
// 王阿姨,注册APP
Cat wangCat = new Cat("大橘","橘猫",3,"小鱼干");
Hamster wangHamster = new Hamster("小白","不知道",1,"白菜");
System.out.println("王阿姨家猫的信息:" +wangCat);
System.out.println("王阿姨家仓鼠的信息:" +wangHamster);
// 王阿姨家的猫叫
wangCat.breaking();
}
}
super注意点:
1.super调用父类的构造方法,必须在构造方法的第一个;
2.super必须只能出现在子类的方法或构造方法中;
3.super和this不能同时调用构造方法;
super与this的比较:
super | this | |
对象 | 代表父类对象的引用 | 代表本身调用者这个对象 |
前提条件 | 只能在继承条件下使用 | 任何条件下 |
构造方法 | 父类的构造方法 | 本类的构造方法 |
六.final
问题: 前面说过多层继承,狗类下面有拉布拉多类,但是拉布拉多下面就没有类了,所以就不能有类继承拉布拉多类,我们应该怎么办。有些父类的变量与方法不能让子类随意修改(如.小区名),我们应该怎么办;
解决: 前面说过final修饰的成员变量和方法是不可修改的,无法被子类继承或覆盖,通俗易懂的说就是用final
定义的类不能再被继承,用fianl
定义的方法不能再被重写,用final
定义的变量是常量且不能再被修改;
使用:
public final class Labrador extends Dogs {
}
// 宠物的行为
public final void eat() {
System.out.println(this.name+"吃饭" +food);
}
public final void sleep() {
System.out.println(this.name+"睡觉");
}
public final void run() {
System.out.println(this.name+"正在奔跑");
}
// 用final定义的变量是常理,而在命令规范中,常理必须大写,单词用下划线隔开
private static final String COMMUNITY_NAME ="NanG";
public static String getCommunityName(){
return COMMUNITY_NAME;
}
补充一些快捷方式:ctrl +shift+u
一键大写,shift+f6
一键更改变量 ;
七. 抽象方法和抽象类的使用
问题1: 如果王大爷注册的时候,不小心点错了,导致了下面这样的情况
// 张大爷,注册APP,使用new实例化
Animal zhangDOg = new Animal();
Animal
本质来说是没有人用的,它是一个抽象的,它抽取了这些猫狗的共性,作为使用;
我们在前面说过抽象与具体的概念,Animal是抽象的,Dogs是具体的,抽象的目的是为了概括(解释)这些具体事物;
于是张大爷打电话给客户说:他不小心点错了,没有给他家的狗注册,而注册成了宠物;
为了避免这种情况的发生我们应该怎么办;
解决: 我们已经知道了Animal是抽象的,所以我们引入抽象类的概念;
1.加入抽象类的关键词是 abstract
,抽象类是不能再被 new
的类,但是它可以被其他的类继承;
public abstract class Animal{
问题2: 前面我们说过重写动物的叫声,但是有一些动物的叫声是我不知道的,所以我们要去网上查一下它们是这么叫的,但是这样的代码有非常多,如果忘记会跟前面一样会输出宠物叫,我们应该这么解决这样问题;
解决: 使用抽象方法,概念如下;
1.只有方法名,没有方法的实现;
2.使用抽象方法那么类必须是抽象类;
3.当一个类继承了一个抽象类时候,该子类必须重写父类中所有抽象方法;
public abstract void breaking();
可以看出仓鼠类没有重写叫声的抽象方法,导致报错
重写后,没有报错
到这里动物社区结束;
八.接口
假如有一个类中定义只有方法,且这些方法都是抽象方法,那么你可以直接把它定义为接口(interface)不用定义为普通的类(class);
如.我创建了一个人类接口,人类是抽象的
package com.microsoft.bean;
public interface Human {
// 接口中所有方法都是抽象的
// 吃饭,每个地区饮食是不一样的
public void eat();
// 喝水,每个地区是不一样的
public void drink();
}
接口的实现,使用implements
之所以报错,是因为没有实现,接口要重写两个抽象方法
package com.microsoft.bean;
public class Chinese implements Human {
@Override
public void eat() {
System.out.println("吃中餐");
}
@Override
public void drink(){
System.out.println("喝热水");
}
}
package com.microsoft.bean;
public class Westerner implements Human{
@Override
public void eat() {
System.out.println("吃西餐");
}
@Override
public void drink(){
System.out.println("喝冷水");
}
}
使用,与抽象类不一样,接口是能new的
问题:抽象类与接口的区别
抽象类:抽象类是针对具体的事物进行抽象,如.前面的猫,狗,仓鼠它们对具体的事物进行抽象,为宠物;
接口:接口是针对动作、行为进行抽象,原因是因为里面只有方法(行为)没有成员变量,且接口中避免出现名词,如.人类的行为动作,所有我们应该把前面的人类接口改成人类的行为接口;
package com.microsoft.bean;
public interface HumanBehaviour {
// 接口中所有方法都是抽象的
// 吃饭,每个地区饮食是不一样的
public void eat();
// 喝水,每个地区是不一样的
public void drink();
}
补充:
1.普通类:只有具体实现;
2.抽象类:具体实现和规范(抽象方法)都有;
3.接口:只有规范! 约束和实现分离:面向接口的编程;
implements可以实现多个接口
public class Frog implements IRunning, ISwimming {
}
九.多态
例子:花木兰替父从军
父类(父亲)
package com.microsoft.bean;
public class HuaHu {
public String name = "花胡";
public int age = 45;
public static void asyMe(){
System.out.println("大家好我叫花胡,今年45岁");
}
public void fight(){
System.out.println("干架");
}
}
子类(女儿)
package com.microsoft.bean;
public class HaMuLan extends HuaHu{
public String name = "我叫花木兰";
public int age = 19;
public void dressing(){
System.out.println("化妆");
}
}
花木兰替父从军
战打完了,花木兰做回自己
package com.microsoft.bean;
public class HuaMuLan extends HuaHu {
public String name = "我叫花木兰";
public int age = 19;
public static void asyMe(){
System.out.println("大家好我叫花木兰,今年19岁");
}
public void dressing() {
System.out.println("化妆");
}
}
可知多态具有多功能;
十. 权限修饰符
Java中的修饰符用于控制类、变量、方法的访问权限和行为。Java中的修饰符可以分为访问修饰符和非访问修饰符两类。
一. 访问修饰符
Java中的访问修饰符包括public、protected、default和private四种。它们的访问权限依次递减,即public > protected > default > private。具体解释如下:
1.public:可以被任何类访问。
2.protected:可以被同一包内的类和不同包中的子类访问。
3.default:可以被同一包内的类访问,不同包中的子类和其他类不能访问。
4.private:只能被同一类内部访问,其他类都不能访问。
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N(说明) | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
二·. 非访问修饰符
Java中的非访问修饰符包括static、final、abstract、synchronized、transient和volatile等。它们的作用如下:
1.static:用于修饰类变量和类方法,表示它们属于类而不是对象,可以通过类名直接访问。
2.final:用于修饰类、变量和方法,表示它们不可改变。
3.abstract:用于修饰抽象类和抽象方法,表示它们没有具体实现,需要子类实现。
4.synchronized:用于修饰方法和代码块,表示它们在多线程环境下是同步的。
5.transient:用于修饰变量,表示它们不会被序列化。
6.volatile:用于修饰变量,表示它们在多线程环境下是可见的。