继承是面向对象三大特征之一。可以使得子类具有父类元素的属性和方法,还可以在子类中重新定义,追加属性和方法。
继承的格式:
-
格式:public class 子类名 extends 父类名
-
案例:public class ZI extends FU{}
-
FU类为父类(superclass),超类,基类
-
ZI类为子类(subclass),派生类,扩展类
继承中子类的特点:
-
子类可以有父类的内容
-
子类也可以有自己特有的内容
//1.创建父类
package extendsDemo;
public class Fu {
public void show(){
System.out.println("Fu中方法被调用了");
}
}
//2.创建子类(子类继承父类)
package extendsDemo;
public class Zi extends Fu{
public void method(){
System.out.println("Zi中方法被调用");
}
}
//3.测试类
package extendsDemo;
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Fu f = new Fu();
f.show();
Zi z= new Zi();
z.method();
z.show();
}
}
//运行结果
Fu中方法被调用了
Zi中方法被调用
Fu中方法被调用了
1.2 继承的好处的弊端
好处:
-
提高代码的复用性(多个类相同的成员可以放到同一个类中)
-
提高代码的维护性(如果方法的代码需要修改,修改一处即可)
弊端:
-
继承让类与类之间产生了关系,类的耦合性增强,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性。
什么时候使用继承?
-
假设法:有两个类A与B,如果他们之间满足A是B的一种,或者B是A的一种,就说明他们之间存在着继承关系,这个时候他们存在着继承关系,可以考虑使用继承,否则不能滥用继承
-
例如:苹果和水果,猫和动物(都可使用继承),猫和狗(不能使用继承)
在子类方法中访问一个变量的访问顺序:
-
子类局部范围找
-
子类成员范围找
-
父类成员范围找
-
如果都没有就报错(不考虑父类以上的)
//1.
package extendsDemo;
public class Fu {
public int height = 185;
public int age = 18;
}
//2.
package extendsDemo;
public class Zi extends Fu{
public int height = 183;
public void method(){
int height = 181;
System.out.println(age);
//局部变量中的height
System.out.println(height);
//this.height访问本类中成员变量中的height
System.out.println(this.height);
//super.height访问父类成员变量中的height
System.out.println(super.height);
}
}
//3.测试类
package extendsDemo;
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Zi z= new Zi();
z.method();
}
}
//运行结果
18
181
183
185
1.4 super关键字
super关键字和this关键字的用法相似之处
-
this:代表本类对象的引用(this关键字指向调用该方法的对象)
-
super:代表父类存储空间的标识(可以理解为父类引用对象)
关键字 | 访问成员变量 | 访问构造方法 | 访问成员方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 | this(.....) 访问本类构造方法 | this.成员方法(....) 访问本类成员方法 |
super | super.成员变量 访问父类成员变量 | super(.....) 访问父类构造方法 | super.成员方法(....) 访问fu类成员方法 |
子类中所有的构造方法默认都会访问父类中无参的构造方法:
-
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化
-
每一个子类构造方法的第一条语句默认都是:super()
如果父类没有无参构造方法,只有带参构造方法,该怎么办?
-
通过使用super关键字去 显示的调用父类带参构造方法
-
在父类中自己提供一个无参构造方法
推荐:自己给出无参构造方法
//1.
package extendsDemo;
public class Fu {
/* public Fu(){
System.out.println("fu中无参构造方法");
}*/
public Fu(int age){
System.out.println("fu中有参构造方法");
}
}
//2.
package extendsDemo;
public class Zi extends Fu{
public Zi(){
// super(); 系统默认调用父类无参构造方法
super(20);
System.out.println("zi中无参构造方法");
}
public Zi(int age){
// super(); 系统默认调用父类无参构造方法
super(19);
System.out.println("zi中有参构造方法");
}
}
//3.测试类
package extendsDemo;
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Zi z= new Zi();
Zi z1 = new Zi(18);
}
}
//运行结果
fu中有参构造方法
zi中无参构造方法
fu中有参构造方法
zi中有参构造方法
1.6 继承中成员方法的访问特点
通过子类对象访问一个方法:(就近原则)
-
子类成员范围找
-
父类成员范围找
-
如果没有就报错(不考虑父类以上)
//1.
package extendsDemo;
public class Fu {
public void show(){
System.out.println("fu中的成员方法被调用");
}
}
//2.
package extendsDemo;
public class Zi extends Fu {
public void method() {
System.out.println("Zi中的成员方法被调用");
}
@Override
public void show() {
super.show(); //调用父类的方法
System.out.println("zi中的成员方法被调用");
}
}
//3.
package extendsDemo;
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Zi z= new Zi();
z.show();
z.method();
}
}
//运行结果
fu中的成员方法被调用
zi中的成员方法被调用
Zi中的成员方法被调用
1.7 super内存图
点击观看视频详解
1.8 方法重写方法重写概述:
-
子类中出现了和父类一摸一样的方法声明
方法重写的应用:
-
当子类需要父类的功能,而主题子类有着自己特有的内容时,可以重写父类方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
@Override
-
是一个注解
-
可以帮助我们检查重写的方法的 方法声明的正确性
方法重写注意事项:
-
私有方法不能被重写(父类中private修饰 的不能在子类中 直接访问。可以通过间接的手段来访问。通过get方法来访问)
-
子类方法的访问权限不能低于父类(public > 默认 > 私有)
//1.
package iphone;
public class Iphone {
public void call(String name){
System.out.println("给"+name+"打电话");
}
}
//2.
package iphone;
public class NewIphone extends Iphone {
@Override //帮助我们检查重写的方法的 方法声明的正确性
public void call(String name) {
System.out.println("打开视频");
// System.out.println("给"+name+"打电话");
super.call(name);
}
}
//3.
package iphone;
public class IphoneDemo {
public static void main(String[] args) {
Iphone p = new Iphone();
p.call("张三");
System.out.println("-------------");
NewIphone np = new NewIphone();
np.call("李四");
}
}
//运行结果
给张三打电话
-------------
打开视频
给李四打电话
1.10 Java中继承的注意事项
-
Java中类只支持单继承,不支持多继承
-
Java支持多层继承(间接继承)
例如:class C extends B,class B extends A,
也就 是说,C 直接继承 B,其实 C 还间接继承 A
1.11 案例1. 老师和学生:
需求:定义老师类和学生类,找到老师类和学生类的共性内容,抽取一个父类,用继承的方式改写代码,并进行测试
思路:
-
共性父类,定义人类(姓名, 年龄)
-
定义老师类,继承人类,给出自己的方法:教书()
-
定义老师类,继承人类,给出自己的方法:学习()
-
定义测试类,写代码测试
//1.定义老师类
package studentAndTeacher;
public class Teacher extends Person {
public Teacher() {
}
public Teacher(String name, int age) {
/* this.name = name;
this.age = age;*/
super(name, age);//通过super()访问父类的带参构造方法
}
public static void teach() {
System.out.println("正在教书");
}
}
//2.定义学生类
package studentAndTeacher;
public class Student extends Person {
public Student() {
}
public Student(String name, int age) {
/*this.name = name;
this.age = age; 其他类不能访问公共类的私有成员*/
super(name, age);//通过super()访问父类的带参构造方法
}
public static void stud() {
System.out.println("正在学习");
}
}
//3.定义公共类
package studentAndTeacher;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void dos(String ds){ //定义公共方法
System.out.println(ds);
}
}
//4.测试类
package studentAndTeacher;
public class Demo {
public static void main(String[] args) {
Student sc = new Student("张三",18);
System.out.println(sc.getAge()+", "+sc.getName());
sc.stud();
sc.dos("学习");
Teacher cc = new Teacher("李四",25);
System.out.println(cc.getAge()+", "+cc.getName());
cc.teach();
cc.dos("教书");
}
}
//运行结果
18, 张三
正在学习
学习
25, 李四
正在教书
教书
2.猫和狗
需求:采用继承的思想实现猫和狗的案例,并在测试类中进行测试
共性:
成员变量:姓名,年龄;构造方法:无参,带参;成员方法:get/set方法
//1.
package catAndDog;
public class Cat extends Animal {
public Cat() {
}
public Cat(String name, int age) {
super(name, age); //调用父
}
public static void show(){
System.out.println("抓老鼠");
}
}
//2.package catAndDog;
public class Dog extends Animal {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
public static void method(){
System.out.println("看家");
}
}
//3.
package catAndDog;
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void fn(String dos){
System.out.println(dos);
}
}
//4.
package catAndDog;
public class Demo {
public static void main(String[] args) {
Dog an = new Dog("ww",2);
System.out.println(an.getName()+", "+an.getAge());
an.method();
an.fn("看门");
Cat ca = new Cat("mm",1);
System.out.println(ca.getName()+", "+ca.getAge());
ca.show();
ca.fn("抓小鸡");
}
}
//运行结果
ww, 2
看家
看门
mm, 1
抓老鼠
抓小鸡
2. 修饰符
2.1包的概述和使用
其实就是文件夹 作用:对类进行分类管理 包的定义格式
-
格式:package包名; (多级包用分开)
-
范例:package com.itheima; 带包的)ava类编译和执行
手动建包:
1.按照以前的格式编译java文件 javac HelloWorld.java
2.手动创建包 在E盘建立文件夹com,然后在com下建立文件夹theima
3.把class文件放到包的最里面 把HelloWorld.class文件放到com下的Jitheimai这个文件夹下
4.带包执行 java com.itheima.HelloWorld
自动建包:
javac-d,HelloWorld.java java com.itheima.HelloWorld
2.2导包的概述和使用使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了 为了简化带包的 *** 作,Jva就提供了导包的功能
导包的格式:
1. 格试:import包名:
2. 范例:import cn.itcast..Teacher
为了简化带包的 *** 作,Jva就提供了导包的功能
导包的格式
格试:import 包名:
-
范例:importcn.itcast.Teacher
修饰符 | 同一个类中 | 同一个包中子类无关类 | 不同包的子类 | 不同包的无关类 |
---|---|---|---|---|
private | yes | no | no | no |
默认 | yes | yes | no | no |
protected | yes | yes | yes | no |
public | yes | yes | yes | yes |
final关键字是最终的意思,可以修饰成员方法,成员变量,类
final修饰的特点:
-
修饰方法:表明该方法是最终的方法,不能被重写
-
修饰变量:表明该变量是常量,不能再次被赋值
-
修饰类:表明该类是最终类,不能被继承
final修饰局部变量
-
变量是基本类型:final修饰指的是基本类型的数据值不能发生改变
-
变量是引用类型:final修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以改变的
//1.
package finalDemo;
public class Student {
public int age = 18;
}
//2.
package finalDemo;
import org.w3c.dom.ls.LSOutput;
public class FinalDemo {
public static void main(String[] args) {
//final修饰基本变量
final int age = 20;
// age = 18; 报错
System.out.println(age);
//final修饰引用类型变量
final Student s = new Student();
s.age = 20;
System.out.println(s.age);
}
}
2.5 static
static关键字是静态的意思,可以修饰成员变量,成员方法
static修饰的特点:
-
被类的所有对象共享;这是判断是否使用静态关键字的条件
-
可以通过类名调用;也可以通过对象名调用;推荐使用类名调用
非静态成员方法:
-
能访问静态的成员变量
-
能访问非静态的成员变量
-
能访问静态的成员方法
-
能访问非静态的成员方法
静态成员方法:
-
能访问静态成员变量
-
能访问静态成员方法
总结:静态成员方法只能访问静态成员
3. 多态 3.1 多态的概述-
同一个对象,在不同时刻表现出来的不同形态
-
多种形态,多种状态,编译和运行有两个不同的状态。
编译期叫做静态绑定。
运行期叫做动态绑定。
-
Animal a = new Cat();
1. a.eat();
2. 父类引用指向子类对象
3. 编译的时候编译器发现a的类型是Animal,所以编译器会去Animal类中找eat()方法
4. 找到了,绑定,编译通过。但是运行的时候和底层堆内存当中的实际对象有关
5. 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。
多态在开发中的作用是: 降低程序的耦合度,提高程序的扩展力。
多态的前提和实现:
-
有继承/实现关系
-
有方法重写
-
有父类引用指向子类对象
成员变量:编译看左边,执行看左边
成员方法:编译看左边,执行看右边
为什么成员变量和成员方法不一样?
-
因为成员方法有重写,成员变量没有
-
多态的好处:提高程序的扩展性
具体体现:定义方法的时候,使用父类型作为参数,将来使用的时候,使用具体的子类型参与 *** 作
-
多态的弊端:不能使用子类的特有功能
向上转型:子--->父 (upcasting) 又被称为自动类型转换:Animal a = new Cat();
向下转型:父--->子 (downcasting) 又被称为强制类型转换:Cat c = (Cat)a; 需要添加强制类型转换符。
什么时候需要向下转型?
1.需要调用或者执行子类对象中特有的方法。
2.必须进行向下转型,才可以调用。
向下转型有风险吗?
1.容易出现ClassCastException(类型转换异常)
怎么避免这个风险?
1. instanceof运算符,可以在程序运行阶段动态的判断某个引用指向的对象是否为某一种类型。
不管是向上转型还是向下转型,首先他们之间必须有继承关系,这样编译器就不会报错。
//1.
package demo_01;
public class Animal {
public void eat(){
System.out.println("吃东西");
}
}
//2.
package demo_01;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void show(){
System.out.println("猫捉老鼠");
}
}
//3.测试类
package demo_01;
public class AnimalDemo {
public static void main(String[] args) {
//父类引用指向子类对象
Animal a = new Cat();
a.eat();
// 报错 a.show();
//向下转型
Cat b = (Cat)a;
b.eat();
b.show();
}
}
3.5 猫和狗(多态版)
//1.
package catAndDog;
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
}
//2.
package catAndDog;
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("饿狗扑食");
}
public void show(){
System.out.println("小狗玩耍");
}
}
//3.测试类
package catAndDog;
import demo_01.Cat;
public class AnimalDemo {
public static void main(String[] args) {
//父类引用指向子类对象,创建对象
Animal a = new Dog("小黄", 6);
a.eat();
// a.show(); 报错
System.out.println("--------------");
//向下转型
Dog d = (Dog) a;
d.eat();
d.show();
System.out.println("--------------");
/* Dog s = new Dog("小红", 2);
s.show();
s.eat();*/
}
}
//运行结果
饿狗扑食
--------------
饿狗扑食
小狗玩耍
--------------
4. 抽象类
4.1 抽象类的概念
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中的如果有抽象方法,该类必须定义为抽象类
package demo_01;
public abstract class Animal {
public abstract void eat();
}
4.2 抽象类的特点
-
抽象类和抽象方法必须用abstract关键字修饰
public abstract class 类名{}
public abstract void eat();
-
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
-
抽象类不能实例化
抽象类如何实例化呢?参照多态的形式,通过子类对象实例化,这叫抽象类多态
-
抽象的子类
1.要么重写抽象类中的所有抽象方法
2.要么是抽象类
4.3 抽象类的成员特点-
成员变量
可以是变量
也可以是常量
-
构造方法
有构造方法,但不能实例化
构造方法的作用是什么呢?用于子类访问父类数据的初始化
-
成员方法
可以有抽象方法:限定子类必须完成某些动作
也可以有非抽象方法:提高代码复用性
4.4 猫和狗(抽象类版)需求:采用抽象类的思想实现猫和狗的案例,并在测试类中进行测试
//1.定义抽象类
package catAndDog;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
//2.
package catAndDog;
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
public void show(){
System.out.println("66666666");
}
}
//3.测试类
package catAndDog;
public class AnimalDemo {
public static void main(String[] args) {
Animal a = new Cat();
a.setName("大菊");
a.setAge(2);
System.out.println(a.getName() + ", " + a.getAge());
a.eat();
System.out.println("--------------");
a = new Cat("小黄", 3);
System.out.println(a.getName() + ", " + a.getAge());
a.eat();
System.out.println("--------------");
Cat b = (Cat) a;
b.show();
}
}
//运行结果
大菊, 2
小猫吃鱼
--------------
小黄, 3
小猫吃鱼
--------------
66666666
5. 接口
5.1 接口概述
-
接口就是一种公共的规范标识,只要符合标准规范,大家可以共享
-
Java中的接口更多体现在对行为的抽象
-
接口用关键字interface修饰
public interface 接口名{}
-
类实现接口implements接口名{}
public class 类名 implements 接口名{}
-
接口不能实例化
1.接口如何实例化? 参照多态的方式,通过实现子类对象实例化,这叫接口实例化
2.多态的形式:具体类多态, 抽象类多态, 接口多态
-
接口实现类
1.要么重写接口中的所有抽象方法
2.要么是抽象类
5.3 接口成员的特点-
成员变量
只能是常量
默认修饰符:public static final(可省略)
-
构造方法
1. 接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在的
2. 一个类如果没有父类,默认继承Object
-
成员方法
-
只能是抽象方法
-
默认修饰符:public abstract
-
需求:对猫和狗进行训练,他们就可以调高,这里加入了调高功能,请采用抽象类和接口来实现猫和狗案例
//1.定义接口
package catAndDog;
public interface Jumpping {
public abstract void jump();
}
//2.定义动物类
package catAndDog;
public abstract class Animal {
private String namne;
private int age;
public Animal() {
}
public Animal(String namne, int age) {
this.namne = namne;
this.age = age;
}
public String getNamne() {
return namne;
}
public void setNamne(String namne) {
this.namne = namne;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
//3.定义猫类
package catAndDog;
public class Cat extends Animal implements Jumpping{
public Cat() {
}
public Cat(String namne, int age) {
super(namne, age);
}
@Override
public void eat() {
System.out.println("小猫吃鱼");
}
@Override
public void jump() {
System.out.println("小猫跳高");
}
}
//4.测试类
package catAndDog;
public class AnimalDemo {
public static void main(String[] args) {
Jumpping j = new Cat();
j.jump();
System.out.println("--------------");
Animal a = new Cat("加菲猫", 3);
System.out.println(a.getNamne() + ", " + a.getAge());
a.eat();
// a.jump(); 报错
System.out.println("--------------");
a = new Cat("大菊", 2);
System.out.println(a.getNamne() + ", " + a.getAge());
a.eat();
}
}
//运行结果
小猫跳高
--------------
加菲猫, 3
小猫吃鱼
--------------
大菊, 2
小猫吃鱼
更多内容请访问博主博客:逸乐的博客 - 今晚一起吃火锅
文章如有纰漏请指出,整理不易多多包涵。
Java后续笔记将持续更新........
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)