什么是继承
继承是把两个类的共性抽取,放到一个类当中
class Dog{
public int length;
public void bark(){
System.out.println(length+"www");
}
}
class Cat{
public int length;
public void miao(){
System.out.println("miao");
}
}
public class L515 {
public static void main(String[] args) {
}
}
通过在创建一个类,另外一两个类extend这个类来实现
class Animal{
public int length;
}
class Dog extends Animal{
// public int length;
public int kemomimi;
public void bark(){
System.out.println(length+"www");
}
}
class Cat extends Animal{
// public int length;
public void miao(){
System.out.println(length+"miao");
}
}
public class L515 {
public static void main(String[] args) {
}
}
现在不需要重定义length了,代码量缩减。此时的Dog叫做子类(派生类),Anim叫做父类(基类,超类)
继承过来后,会保持原有属性,扩展父类属性
public class L515 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.kemomimi=1;
dog.length=2;
}
}
子类访问父类的成员变量
当子类和父类不存在同名变量的时候
class Test{
public int a = 1;
public int b = 2;
}
class Homewark extends Test{
public int c = 3;
public int d = 4;
public void print(){
System.out.println(this.c);
System.out.println(this.b);
System.out.println(this.c);
System.out.println(this.d);
}
}
public class L515 {
public static void main(String[] args) {
Homewark homewark = new Homewark();
homewark.print();
}
}
有同名状况的时候
class Test{
public int c = 1;
public int b = 2;
}
class Homewark extends Test{
public int c = 3;
public int d = 4;
public void print(){
System.out.println(this.c);
System.out.println(this.b);
System.out.println(this.c);
System.out.println(this.d);
}
}
//如果子类中有同名的,输出会优先访问子类自己的方法
//如果访问的成员变量子类没有,则会访问父类继承的,父类如果也没有则会报错
如果需要访问父类的c .成员变量改成super.c;
super是子类从父类继承的空间的地址
class Test{
public int c = 1;
public int b = 2;
}
class Homewark extends Test{
public int c = 3;
public int d = 4;
public void print(){
System.out.println(super.c);
System.out.println(this.b);
System.out.println(this.c);
System.out.println(this.d);
}
}
子类访问父类成员方法
class Test{
public int c = 1;
public int b = 2;
public void resolve(){
System.out.println("父类");
}
}
class Homewark extends Test{
public int c = 3;
public int d = 4;
public void print(){
System.out.println(super.c);
System.out.println(this.b);
System.out.println(this.c);
System.out.println(this.d);
}
public void method(){
System.out.println("子类");
}
}
public class L515 {
public static void main(String[] args) {
Homewark homewark = new Homewark();
homewark.print();
homewark.method();
homewark.resolve();
}
}
有同名状况的时候
优先原理同成员变量的原理。需要在非静态方法里用super.父类方法名来进行访问
public void method(){
System.out.println("子类");
super.method();
}
只能在非静态方法中使用,static和super不能共存。
注意
当我们给父类按照一般的情况写上构造方法时,子类会保错
子类对象构造完成之前,需要先对父类的成员初始化。
需要在子类新建的构造方法上加上父类构造方法的参数,内部进行super
public Homewark(int c, int d){
super(c,d);
//super只能放在第一行,this也要放到第一行,因此this和super不能共存
}
注意:
一个类的两个方法,无论是在同一个类中声明的,还是由一个类继承的,都是重载。
protect关键字
在默认的功能下加了不同包的子类下也可以使用。
在L520下新建一个类
class dog{
protected int longth =1;
}
public class L520 {
}
然后在test下也写上子类并用super来调用。
class Animal extends dog{
public void print(){
System.out.println(super.longth);
}
}
public class test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.print();
}
}
Java中的继承
1.单继承,一个类只能继承另外一个类,不能继承多个类。
class Dog extends Cat{
}
class Cat{
}
class Chicken{
}
public class L520 {
}
2.多重继承。
class Dog {
}
class Cat extends Dog{
}
class Chicken extends Cat{
}
public class L520 {
}
//在一个类前加上final的时候,这个类就不会被继承了。
此时狗是猫的父类,猫是鸡的父类,就是多重继承,多重继承最底下的会保留上层的成员变量和成员方法。
3.不同类继承同一类。
class Dog {
}
class Cat extends Dog{
}
class Chicken extends Dog{
}
public class L520 {
}
4.一个类不能继承两个类。
但是3中,一直继承下去一个类过于冗杂,因此我们有了接口。
继承和组合
组合是表达类之间关系的方式,也能达到代码重用的效果。,仅仅是将一个类的实例作为另外一个类的字段
class Teacher{
}
class Student{
}
class School{
private Student[] students;
private Teacher[] teachers;
}
public class L520 {
public static void main(String[] args) {
}
}
学生和老师两个类中的成员变量成员方法等,学校类中都可以拿到。相对于继承,我们优先考虑组合。
多态
加上多种形态,具体点加上去完成某种行为,不同对象去完成时会有不同的状态。
要实现多态,需要满足两个要求,一个是向上转型,另一个是重写。
向上转型
先写一个普通代码:
class Teacher{
private String name;
//后面加上构造方法,getterandsetter和tostring
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name=" + name +
'}';
}
public void teach(){
System.out.println("正在上课");
}
}
class Student extends Teacher{
//初始化父类对象
public Student(String name) {
super(name);
}
public void shout(){
System.out.println(getName()+"为什么不下课");
}
}
class School extends Teacher{
public School(String name) {
super(name);
}
public void over(){
System.out.println(getName()+"应该下课啦");
}
}
public class L520 {
public static void main(String[] args) {
Student student = new Student("王鸿");
student.shout();
}
}
向上转型就是把student赋给teacher;
public class L520 {
public static void main(String[] args) {
Student student = new Student("王鸿");
Teacher teacher =student;
//或者写成:
// Teacher teacher = new Student("王鸿");
}
}
//也就是把子类给父类了。
向上转型可以成功因为student是teacher的子类。
此时只能调用teacher自己内部的东西,不能调用子类的东西。
还有一种向上转型的方式:方法的传参
public class L520 {
public static void func(Teacher teacher){
}
public static void main(String[] args) {
Student student = new Student("王鸿");
func(student);
}
}
在student是teacher子类的情况下,通过主类的函数去直接传入父类的形参,然后在主函数中调用参数为子类的方法。
这个时候只需要new子类的对象。
还有一种:方法的返回值
public static Teacher func(){
return new Student("画画");
}
public static void main(String[] args) {
Student student = new Student("王鸿");
func(student);
}
在返回值上,同样可以发生向上转型
向下转型(不经常使用,因为不安全)
public static void main(String[] args) {
// Student student = new Student("王鸿");
// Teacher teacher = student;
Teacher teacher =new Teacher("王鸿");
Student student = (Student) teacher;
}
但是当我们运行时会报错,需要:
public static void main(String[] args) {
// Student student = new Student("王鸿");
// Teacher teacher = student;
Teacher teacher =new Teacher("王鸿");
if(teacher instanceof Student) {
Student student = (Student) teacher;
student.shout();
}
}
if是为了判断这个引用是不是这个类型的实例
重写(复写)(覆盖)
重写要求:
方法名相同,
方法的参数列表相同(个数,类型,顺序)
方法的返回值相同,(方法返回值可以不相同,比如子类的返回值和父类的返回值是父子类关系,也叫协变类型,也可以构成重载)
static的方法不能被重写,
private的方法不能被重写,
子类修饰的访问修饰符的权限,需要大于等于父类的访问修饰符的权限。
不想重写方法的话加上final就可以避免被重写,术语叫做密封方法。
以上就可以实现多态了,多态的基础上加上通过父类的引用,调用这个重写的方法就可以构成动态绑定。
动态绑定(运行时绑定)
在编译的时候,父类的方法还会是自己的,在运行的时候,程序发生了动态绑定,调到了子类自己的。
而静态绑定呢,则是在编译的时候,根据用户所传递的实参类型就确定了调用的具体方法,例如函数的重载,因此也称前期绑定。
class Teacher{
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name=" + name +
'}';
}
//此时teacher这个父类中有teach和shout两个方法。
public void teach(){
System.out.println("正在上课");
}
public void shout(){
}
}
class Student extends Teacher{
public Student(String name) {
super(name);
}
//但是子类也有两个同名的方法。
public void shout(){
System.out.println(getName()+"为什么不下课");
}
public void teach(){
System.out.println("正在上课啊");
}
}
向上转型后,父类一般是调用不了子类方法的,但是当父类和子类发生了多态的时候,子类父类都有同名的方法,此时使用父类名就可以引用子类的具体方法,而与父类另一同名方法的具体实现无关。
动态绑定是多态的一个基础。