面向对象高级阶

1、继承
// getter 方法,
// 作用是将构造器传入的属性通过 getter方法 赋值给本类中封装好的属性,
// 再通过构造器将已经赋值的属性传出去
// setter 方法,
// 作用是将其他类中通过调用方法 调用这个类中的setter 方法 对封装的属性进行设置,
// 最后该设置好的属性,通过构造器传出去
//
// 所以在放封装属性的类中是:
// 1、先封装属性,
// 2、再写有参、无参的用来传入、传出变量或常量的构造器
// 3、再然后才写getter 、setter 方法

// setter 方法中是要对传入的变量或常量进行设置的,
// 对传入的变量或常量进行赋值给封装好的变量属性的,
// 即先传入变量或常量,再进行设置
// 所以setter( ) 中的括号要写变量的类型、变量的名称

继承实例
public class Inheritance {

public static void main(String[] args) {
    student2 s = new student2();
    s.setName("张三");
    s.setAge(18);
    s.say();


}

}

class person2{
private String name;
private int age;

public person2(String name, int age) {
    this.name = name;
    this.age = age;
}
public person2() {
}

// getter  、  setter  方法都是将值设置好( 赋值给封装的变量 )供外部调用的类设置和获取的,
// 外部调用的类再通过有参或无参的构造器传入或传出相应的变量

// getter 方法,
// 作用是将构造器传入的属性通过 getter方法 赋值给本类中封装好的属性,
// 再通过构造器将已经赋值的属性传出去
// setter 方法,
// 作用是将其他类中通过调用方法 调用这个类中的setter 方法  对封装的属性进行设置,
// 最后该设置好的属性,通过构造器传出去
//
// 所以在放封装属性的类中是:
// 1、先封装属性,
// 2、再写有参、无参的用来传入、传出变量或常量的构造器
// 3、再然后才写getter 、setter 方法

public String getName() {
    return name;
}

public void setName(String name) {  // setter 方法中是要对传入的变量或常量进行设置的,
                                    // 对传入的变量或常量进行赋值给封装好的变量属性的,
                                    // 即先传入变量或常量,再进行设置
                                    // 所以setter( ) 中的括号要写变量的类型、变量的名称
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public void say(){
    System.out.println("我是"+name+",今年"+age+"岁了");
}

}

class student2 extends person2{

}

C++ 里有多继承(比如:一个孩子有多个爹 ,缺点:当继承的爹有双重东西的时候就容易出现错乱)
Java 只有单继承( 一个子类只能有一个父类 ),和多重继承,没有多继承

继承代码在栈执行时,先看堆内存的子类是否有 封装的属性、构造器、getter、setter 方法,
有的话就不在创建父类内存,不在使用父类的封装的属性、构造器、getter、setter 方法,及其他方法了,
如果没有,堆内存就创建父类内存,再使用父类的封装的属性、构造器、getter、setter 方法,及其他方法,
就是一层一层递进上去,
如果所有的父类都没有封装的属性、构造器、getter、setter 方法,及其他方法的话,系统就会报错了

继承代码在栈执行时,堆内存是先创建父类的内存,在创建子类内存、
然后由子类的对象指向父类的内存,再操作

2、super
通过 super ( 即传入 或 传出数据 )访问父类的构造器
在访问( 即传入 或 传出数据 )父类时,是默认用无参构造器访问的,
当父类没有无参构造器时,子类在继承时就要明确地用 super 来调用,不用 super 来调用会报错

    // 如果没写super ,
    // 是编译器自动省略了调用父类的无参构造器
    // 这里是通过 super 指定 调用父类有参的构造器
    // 调用 super 构造器的代码,必须写在子类构造器的第一行

    /*this 关键字
    在一个构造方法中调用另一个构造方法时
    调用的代码  必须写在构造方法的第一行
    原因:this 关键字调用的对象时在堆内存创建对象时( 即对象在堆内存初始化 )还没有完毕,
    要等待对象在堆内存初始化完毕,然后再执行其他的逻辑,否则会报错*/

    // 所以 super 和 this 关键字 不能出现在同一个代码块中
    
    // super 在调用成员属性时不用写在构造方法的第一行

super 实例
public class Inheritance {

public static void main(String[] args) {
    student2 s = new student2();
  /*  s.setName("张三");
    s.setAge(18);*/
    s.say();


}

}

class person2{ // 父类
private String name;
private int age;
public String sex;

public person2(String name, int age) {
    this.name = name;
    this.age = age;
}
public person2() {
}

// getter  、  setter  方法都是将值设置好( 赋值给封装的变量 )供外部调用的类设置和获取的,
// 外部调用的类再通过有参或无参的构造器传入或传出相应的变量

// getter 方法,
// 作用是将构造器传入的属性通过 getter方法 赋值给本类中封装好的属性,
// 再通过构造器将已经赋值的属性传出去
// setter 方法,
// 作用是将其他类中通过调用方法 调用这个类中的setter 方法  对封装的属性进行设置,
// 最后该设置好的属性,通过构造器传出去
//
// 所以在放封装属性的类中是:
// 1、先封装属性,
// 2、再写有参、无参的用来传入、传出变量或常量的构造器
// 3、再然后才写getter 、setter 方法

public String getName() {
    return name;
}

public void setName(String name) {  // setter 方法中是要对传入的变量或常量进行设置的,
                                    // 对传入的变量或常量进行赋值给封装好的变量属性的,
                                    // 即先传入变量或常量,再进行设置
                                    // 所以setter( ) 中的括号要写变量的类型、变量的名称
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public void say(){
    System.out.println("我是"+name+",性别:"+sex+",今年"+age+"岁了");
}

}

class student2 extends person2{ //子类继承父类

public student2() {
    super("无名称",18);  // 这一行,表示自动被创建的父类对象,调用构造方法,必须在代码块的第一行,
                                   // 子类创建多少个,就会自动创建多少个父类对象
    super.sex = "男";              // super 调用成员属性,不比在代码块的第一行

    super.setName("张三丰");        // 通过super 访问父类的方法,也不用在代码块的第一行

    // 如果没写super ,
    // 是编译器自动省略了调用父类的无参构造器
    // 这里是通过 super 指定 调用父类有参的构造器
    // 调用 super 构造器的代码,必须写在子类构造器的第一行

    /*this 关键字
    在一个构造方法中调用另一个构造方法时
    调用的代码  必须写在构造方法的第一行
    原因:this 关键字调用的对象时在堆内存创建对象时( 即对象在堆内存初始化 )还没有完毕,
    要等待对象在堆内存初始化完毕,然后再执行其他的逻辑,否则会报错*/

    // 所以 super 和 this 关键字 不能出现在同一个代码块中

    // super 在调用成员属性时不用写在构造方法的第一行
}

}
3、重写
重写定义 : 方法的重写,只发生在类的继承中
// 方法的重写,括号里的内容为参数列表,

重写时,
1 ①、这个子类与父类的格式要完全相同,
②、参数列表也要完全相同,
③、返回类必须相同
2、访问权限 :父类的访问权限不能比子类的访问权限更低
3、父类的成员方法 只能被 他子类的成员方法重写
4、声明为 static 和 private 的方法不能被重写但能够被再次声明,
因为静态static 本身就没有继承 ,跟对象没有关系 ;
private 私有的东西本身就没有被继承,也就没有重写

重写 :发生在子父类当中
重载:发生在一个类里面,一个类里面有多个方法,方法的名称相同,
但参数列表的长度、类型、类型的顺序不同,这时才会构成重载
重写( overwrite ) 与 重载( overload ) 的区别
①发生位置:
重写: 子父类中
重载: 一个类中

②参数列表限制:
重写: 必须相同
重载: 必须不同

③返回值类型:
重写: 返回值类型必须一致
重载: 与返回值类型无关

④访问权限:
重写: 子类的访问权限必须大于等于 ( ≥ )父类的访问权限
重载: 与访问权限无关

⑤异常处理:
重写: 异常范围可以更小,但不能抛出新的异常
重载: 与异常无关

public class overWrite {
// 重写
public static void main(String[] args) {
student s = new student();
s.say();

}

}

class person { // 父类
public void say(){
System.out.println(“床前明月光,疑是地上霜!”);
}
}

class student extends person{ // 子类
public void say(){ // 方法的重写,括号里的内容为参数列表,
// 1、重写时,1、这个子类与父类的格式要完全相同,2、参数列表也要完全相同,3、返回类必须相同
// 2、访问权限 :父类的访问权限不能比子类的访问权限更低
// 3、父类的成员方法 只能被 他子类的成员方法重写
// 4、声明为 static 和 private 的方法不能被重写但能够被再次声明,
// 因为静态static 本身就没有继承 ,跟对象没有关系;
// private 私有的东西本身就没有被继承,也就没有重写
System.out.println(“锄禾日当午,汗滴禾下土!!”);
}
}

4、final
属性是有默认值的,int 属性的默认值是零( 0 );
final 修饰全局常量时 ( public static finsal ) ,表示是全局常量是不可以改变的,已经是常量了

① final 用于修饰属性、变量,
② 修饰后变成常量,无法对其再进行赋值
③ final 修饰的局部变量最多只可以赋值一次( 可以先声明,再赋值 )
④ final 修饰的是成员属性,必须在声明时就要赋值
⑤ 全局常量 ( public static final )
⑥ final 修饰的类不可以被继承
⑦ final 修饰的方法不能,不能被子类重写
⑧ 常量命名的规范:
由一个或多个单词组成,单词之间必须使用下划线隔开,单词中所有字母大写
例如 : SQL_INSERT

final 修饰实例
public class finalKeyword {

final int a = 0;  // main 方法前是成员变量,这里修饰成员属性时,必须在声明时就要赋值

public static void main(String[] args) {
    // final 修饰后变量只能变为常量
    final int b;  // main 方法后面是局部变量,
                  // 当修饰变量未赋值时,变量只能赋值一次,后面只能是常量了
    b = 10;

}

}

5、抽象类
抽象类概念 : 抽象类必须使用 abstract class 声明
一个抽象类中可以没有 抽象方法,但 抽象方法 必须写在抽象类 或者 接口中

  抽象类 格式 :  abstract  class  类名    {      }      //  抽象类

抽象方法:只声明而未实现的方法,称为抽象方法 ( 未实现指的是:没有 { } 方法体 ),
抽象方法必须使用 abstract 关键字 声明

              抽象方法格式 : 
              abstract  class  类名  {   //  抽象类
                            public  abstract  class  方法名(  ) ;   //  抽象方法,只声明而未实现                                
                        }

抽象类不能被实例化:
① 抽象类本身是不能直接进行实例化操作的,即不能直接使用关键字 new 完成;
② 一个抽象类必须被子类所继承,
被继承的子类( 如果不是抽象类 )则必须要写出 抽象类 中的 全部 抽象方法

常见问题
① 抽象类不能使用 final 声明,因为 final 修饰的类是不能有子类的,
而抽象类想要实例化就必须要有子类继承,在子类中补全所有的 抽象方法,
所以抽象类必须有子类才有意义
② 抽象类也可以有自己的 构造器 ,而且 子类 对象实例化 的时候的 流程 与 普通类的 继承 是一样的,
都是要调用父类的构造器 ( 默认是无参的 ),之后再调用子类自己的构造方法

规范 : 一个点Java文件 ( . Java ) 文件只编写一个类

在继承抽象类时,子类本身可以是抽象的类,子类也可以不是抽象类,

但当继承抽象类的 子类 不是 抽象类 时,子类要将抽象方法实例化,
就是写上与继承的父类抽象类里的抽象方法格式一致,但要去掉 abstract

抽象类可以有抽象的部分,也可以有不抽象的部分

接口比抽象类更抽象

子类在堆内存创建时是先创建父类的对象

抽象类可以有构造器,不能 通过 new 方法创建对象,
但是 JVM ( Java Virtual Machine ) 内部可以通过其他方法创建对象

抽象类 与 普通类 的区别:
① 抽象类 必须用 public 或 protected 修饰 ( 如果为 private 修饰,那么子类则无法继承,也无法实现其抽象方法 ),
如果没有写权限修饰符时,则默认为 public ,。而不是之前说的默认为 default
② 抽象类 不可以使用 new 关键字创建对象,
但是子类在创建对象时,抽象父类也会被 JVM ( Java Virtual Machine )实列化
③ 如果一个子类继承抽象类,那么必须实现其所有的 抽象方法,
如果有未实现的抽象方法,那么子类也必须定义为抽象类

抽象方法实例
public class abstractClass {
public static void main(String[] args) {
student3 s = new student3();
s.say();

}

}

abstract class personel{ // 抽象类

public personel(){            // 抽象类也可以有构造方法,子类在堆内存中创建时,父类抽象类对象已经创建 且 执行
    System.out.println("构造方法执行了");
}
public abstract void say();    // 抽象方法

}

class student3 extends personel{

@Override
public void say() {
    System.out.println("我是一个学生,我要好好学习,天天向上");

}

}

6、接口
接口定义 :
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口

  接口格式 : 
  interface   接口名称  {
   public  static  final   属性  ;                //   全局常量  
  public abstract void   方法名 (  )  ;        //   抽象方法
  }

接口的实现 implements
接口可以多实现

接口实现的格式:
class 子类 implements 父接口1,父接口2 … { // 接口的实现

                                     }

一个类,既要实现 接口 又要实现 继承 的格式 :
class 子类 extends 父类 implements 父接口1,父接口2 … {

                                    }

面向接口编程思想 :
接口是定义( 规范、约束 )与实现( 名 实 分离的 原则 )的分离
优点:
① 降低程序的 耦合性 ( 使程序代码块需求不至于太过 粘合 )
② 易于程序的扩展
③ 有利于程序的维护

全局常量 和 抽象方法的简写 :
因为接口本身就是由全局常量 和 抽象方法组成,所以接口中的成员定义可以简写 :
① 全局常量编写时,可以省略 public static final 关键字,
例如:
public static final String INFO = " 内容 " ;
简写后 :
String INFO = " 内容 " ;

② 抽象方法编写时,可以省略 public abstract 关键字,
例如:
public abstract void print ( ) ;
简写后:
void print ( ) ;

接口的继承:
接口因为都是抽象部分,不存在具体的实现,所以允许多继承,
例如:
interface C extends A , B { // 接口的多继承

                  }

接口类注意要点 :
① 接口中不能有实现的东西,不能有方法代码块 { }
② 子类在实现接口类时,一定要在代码中添加实现方法
③ 子类在实现接口的抽象方法时,必须将接口中所有的抽象方法写出来
④ 接口中的全局常量不一定要写出来,
⑤ 如果接口想要使用,必须依靠子类( 子类如果不是抽象类的话 ),要实现接口中的 所有 抽象方法




接口 和 抽象类 的区别 :
① 抽象类要被子类继承,接口要被类实现
② 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法
③ 接口里的定义变量只能是公共的静态的常量( 即 全局常量 : public static final 属性 ;),
抽象类中的变量是普通变量
④ 抽象类通过继承来使用,无法多继承,接口通过实现来使用,可以多实现
⑤ 抽象类中可以包含 static 方法,但是接口中不允许( 静态方法不能被子类重写,因此接口中不能声明静态方法 )
⑥ 接口不能有构造器,但是抽象类可以有

public class interfaceKnowledgePoint {
public static void main(String[] args) {
village v = new village();
v.say();
}
}

interface personner{
int a = 20 ;
void say() ;
void jump();

}

class village implements personner{

@Override
public void say() {       // 子类在实现接口的抽象方法时,必须将接口中所有的抽象方法写出来
    System.out.println("我是一个村民,今年"+a+"岁了"); // 但接口中的全局常量不一定要写出来,
                                                  // 如这里的 " a " ,代码逻辑上可以省略
}

@Override
public void jump() {      // 子类在实现接口的抽象方法时,必须将接口中所有的抽象方法写出来
    System.out.println(1);
}

}

7、多态
父类引用指向子类对象
instances

8、object 类是 所有类的父类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值