java面向对象的编程

面向对象的编程

一、面向对象和面向过程

1.面向过程

面向过程注重怎么做

2.面向对象

面向对象注重由谁来做

3.二者联系

相互联系,相辅相成。面向对象需要对全局进行构建,充当一个指挥者,指挥这个任务由哪个对象来做,那个任务由哪个对象来做,但是每个对象具体怎么做还是要用到面向过程的思维方式来完成。

二、对象和类的关系

1.对象

对象是具体的事物,实例,例如一个杯子就是一个对象

2.类

类就是对象的像的提取,也就是说是对所有对象的相似部分进行提取,组成的一个抽象的概念,例如人就是一个类,它是将很多我们相同的性质的提取

三、局部变量和成员变量的区别

1.局部变量

局部变量定义在方法中的或者定义在代码块中的变量;

局部变量的作用域仅限于该方法内部,或者包含该局部变量的代码块内部

局部变量在定义时必须要进行变量的初始化赋值,不然在后续方法内部使用时会报错;

局部变量的内存是在栈中;

局部变量的作用时间是从方法执行到结束 ;

2.成员变量

成员变量就是定义在方法外类里面的变量,是属性;

成员变量的作用域是整个类内部

成员变量在定义的时候不需要对该成员变量进行初始化赋值,后续使用的时候在进行赋值,因为成员变量有默认值;

成员变量的内存是在堆中;

成员变量作用的时间是从该对象创建到销毁;

四、创建类

类中要有属性(成员变量)、方法

package com.heyanshu1;

/**
 * @author: HeJun-Qi
 * @data: 2021/7/24  15:58
 * @description: com.heyanshu1
 * @java_version: 12.0.2
 */
public class object1 {
    //创建一个空构造器(必须要有这样一个空构造器)
    public object1(){            //一般不会在空构造器中对属性进行初始化赋值,因为那样的话每个对象的属性就一样了

    }
    //属性
    String name;
    int age;
    double hight;
    double weight;
    //方法
    public void sleep(){
        System.out.println("今天随眠质量良好!");
    }
}

五、创建对象

  1. 在完成类的创建后单独创建一个test类,创建类的作用就是为了调用该类中方法

    package com.heyanshu1;
    /**
     * @author: HeJun-Qi
     * @data: 2021/7/25  15:30
     * @description: com.heyanshu1
     * @java_version: 12.0.2
     */
    public class test1 {
        public static void main(String[] args) {
            object1 accept=new object1();     //这里用new来调用方法,不像以前用点来调用
            System.out.println(accept.age);
            System.out.println(accept.name);
            System.out.println(accept.weight);
            System.out.println(accept.hight);
        }
    }
    
    
  2. 创建一个所需要类的具体的对象/实例/实体

    //代码格式:类名 接收、对象在内存空间中开辟的地址名=new 类名
     //   例如:
    object1 p=new object1;    //这里的P接收的是创建的对象在空间中的地址,后续中通过这个地址到堆中去找到对应的空间,然后找到对象中的相关属性的值
    System.out.println(p.age);
    System.out.println(p.name);
    System.out.println(p.hight);    
    
  3. 在计算机内部创建对象的过程

    • 当第一次遇见某个类时,进入类加载器classloader中(只在第一次遇见该类时加载一次,之后再创建对象的时候就不会进入了)
    • 加载完成后,创建对象,为这个对象在堆中开辟空间并为创建的对象进行初始化动作(其实在加载完成后对象就已经生成了,所以在进入加载器的时候会有个this,同时在对象创建完成后也随即给对象进行初始化赋值,这里的初始化赋值其实是对类中的属性进行默认的赋值操作)
    • 之后进入类中去找构造器

    4.new关键字的作用

    1. 实际上关键字是在调用一个方法,这个方法叫做构造方法(构造器)
    2. 当我们在调用构造器的时候,如果我们自己没有编写构造器的话,系统会默认给你分配一个构造器,只是我们看不见(系统默认分配的构造器的话debug调试就看不见一步步执行赋值操作,所以我们点下一步就直接退出类,回去执行下一行代码)
    3. 构造器的作用不是创建对象,因为在调用构造器前就已经在内存中创建好了,并且属性有默认初始化的值
    4. 调用构造器的作用是对属性进行赋值操作

六、构造器的重载

1.什么是构造器的重载

构造器的重载就是构造器的名称相同,但是形参列表不同的构造器

2.为什么要构造器的重载

因为我们要保证空构造器的存在,又要保证构建的对象的属性值可变

3.构造器的重载需要注意的问题

  • 重载构造器的形参名要和对象的属性名一样的话,就必须在属性名前面加上this.前缀,只是因为程序有就近原则,当不指定参数时默认每个参数就是最近的那个参数,这样就会导致在用new调用构造器时我们的形参不能赋值给属性值(这里的this就是我们创建的对象)
  • 构造器赋值适用于当对象有多个属性需要进行赋值操作

4.代码展示

1.创建类
package com.heyanshu1;

/**
 * @author: HeJun-Qi
 * @data: 2021/7/24  15:58
 * @description: com.heyanshu1
 * @java_version: 12.0.2
 */
public class object1 {          //创建object1类
    public object1(){           //创建空构造器,不能再里面对属性赋值操作
        /*age=19;
        name="xiaxia";
        hight=165;
        weight=96;*/
    }
    public object1(String name,int age,double weight,double hight){      //创建构造器重载,改变形参的个数
        this.age=age;           //由于形参名和属性名相同,所以必须在属性名前面加上this.前缀
        this.name=name;
        this.weight=weight;
        this.hight=hight;
    }
    String name;             //定义属性
    int age;
    double hight;
    double weight;
    public void sleep(){             //定义方法
        System.out.println("今天随眠质量良好!");
    }
}

2.创建测试类
package com.heyanshu1;

/**
 * @author: HeJun-Qi
 * @data: 2021/7/25  15:30
 * @description: com.heyanshu1
 * @java_version: 12.0.2
 */
public class test1 {
    public static void main(String[] args) {
        object1 accept=new object1("xiaxia",19,95,167);    //这一步在内存中已经创建了对象,new构造器只是对类中属性进行赋值操作。
        //在创建对象的时候直接在构造器形参中赋值,不用在使用accept.age=19这种赋值方式
        System.out.println(accept.age);
        System.out.println(accept.name);
        System.out.println(accept.weight);
        System.out.println(accept.hight);
    }
}

七、创建对象的内存分析

1.创建对象的语句

//例如已经创建了一个hoom类
home p=new home;

2.创建该对象的内存分析

  1. 通过类加载器加载home类,并将 home .class 字节码文件信息所对应的方法传到方法区,同时在堆中存放字节码信息,根据字节码信息以该方法为模板在堆中创建对象,同时对其进行地址分配和默认初始化赋值

  2. 通过new关键字在home类中去找构造器

  3. 找到构造器后将值赋值给属性,,构造器的内存是在栈中开辟的构造器栈帧中,里面有用户需要赋值给属性的值,一般类型数据直接将所需值赋值给形参,引用型数据如string类型的数据,需要将该数据放在方法区中开辟的字符串常量池中,然后将改值对应的地址码传给形参

  4. 完成属性赋值后,将堆中创建的方法地址赋值给p,栈中为main方法开辟的栈帧,p是该栈帧中的变量

  5. 后续程序要用到该对象的相关属性的时候可以直接调用p.属性来进行属性的输出

  6. 在调用p的时候首先通过地址进入堆中找到方法所在的内存空间,然后将需要的属性值调用出来赋值给其他变量

八、this的使用

1. this的含义

  1. 在创建对象的时候,进入构造器对属性进行赋值前,存在的this指代的是我正在创建的对象,里面有该对象所具备的属性以及默认初始值
  2. 当在进行调用的时候,存在的this 指代的是当前正在调用的对象

2. this 的用法

  1. 修饰属性:当构造器中的形参名和属性名相同时,在对属性进行赋值时需要在属性名前面加上this. 来指代名为对象的属性名,(这个this指代的是调用该方法的对象,所以this.就相当于对象.)

    public person(){
        int gae;
        String name;
        double height;
        public person(){
            
        }
        public person(int age,String name,double height){
            this.age=age;       //形参与属性名相同所以需要加上this.来修饰属性名,这里的this是正在创建的对象
            this.name=name;     //同理这两句也可以用this(age,name)
            this.height=height;
        }
          public person(int age,String name){
            this.age=age;         //这一句可以用this调用构造器来完成:this(age);表示调用一个参数的构造器
            this.name=name;
        }
          public person(int age){
            this.age=age;
        }
        public void play(){
            int age=10;
            System.out.println(age);
             System.out.println(name);
            System.out.println(this.age);      //局部变量age和属性名相同,所以要加上this.,这个this指代的是调用paly方法的对象
            System.out.prinltn("I Like playing basketboll!")
        }
        public void sleep(){
            System.out.println("睡觉真不错!")
        }
    }
    
  2. 修饰方法:当一个方法里面的代码和另外一个方法里面的代码有相同的部分时,可以用this调用方法到另外一个方法里,减少另外一个方法中重复写相同的代码(注意当调用方法时,调用语句必须写在最前面)

    public void read(){
        System.out.println("我喜欢看《小王子》");
    	System.out.println("我喜欢看《红与黑》");      					
    }
     public void aiHao(){
         System.out.println("我喜欢看《小王子》");
    	System.out.println("我喜欢看《红与黑》");       //这两句完全可以用:this.read()来代替,只是这里的this.可以省略,因为这两个方法在同一个类中
         //这里的this指代的是test类中person p=new person,中的p,相当于在使用p.aiHao这句代码调用aiHao这个方法的时候,先进来执行p.read,执行这句的时候就会跳转到read方法中去,执行完后read后再接着执行aiHao方法后面的内容
         System.out.println("我喜欢看电影");
    	System.out.println("我喜欢打游戏");    
     }
    
    
    
  3. 修饰构造器:

    public person(){
        int gae;
        String name;
        double height;
        public person(){
            
        }
        public person(int age,String name,double height){
            this.age=age;     
            this.name=name;     //同理这两句也可以用this(age,name)
            this.height=height;
        }
          public person(int age,String name){
            this.age=age;         //这一句可以用this调用构造器来完成:this(age);表示调用一个参数的构造器
            this.name=name;
        }
          public person(int age){
            this.age=age;
        }
    

九、static 的使用

1. static 在内存中的含义

在创建对象的时候,进行类加载时除了将类的字节码信息加载到方法区外,还有将定义的静态属性放入方法区的静态域中,并进行初始化赋值。放在静态域中的属性被整个类所共享,也就是说整个类中所以的该属性都只能有同一个值,一个对象中更改了静态属性那么所有对象中该属性也跟着变,公用这一个属性

2. static 使用的场景

当方法中有,所有使用该属性的对象,都是一样的值,的时候可以在方法中进行:类名.需要的静态属性名=想要赋的值;

3. static 的使用方法

public class heYanShu(){
    static int age;
    String name;
    double height;
    //heYanShu.age=18;不能在这对静态变量age赋值操作
    public heYanShu(){
        
    }
    public heYanShu(String name,double height){
        this.name=name;
        this.height=height;
    }
    public static void main(String[] args){         //要是这里定义的方法不是static类型的话,在调用age这个static修饰的属性的时候会报错,因为static修饰的方法只能直接调用static修饰的方法或者属性
         heYanShu.age=18;
        heYanShu p1=new heYanShu("xiaohua",182);    
       System.out.println(p1.name);
       System.out.println( heYanShu.age);
       System.out.println(p1.height);
        heYanShu p2=new heYanShu("xiaoming",176);    
       System.out.println(p2.name);
       System.out.println( heYanShu.age);
       System.out.println(p2.height); 
      
    }
}


运行结果:两个人都是18岁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mc3hXltE-1661865921836)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210728155031105.png)]

如果在属性定义后对静态域变量age进行赋值操作,是在构造器中对age变量进行赋值操作,那么在运行结果中该类中所有age变量的值会是最后一次age变量所赋的值

package com.heyanshu2;

/**
 * @author: heYanShu
 * @data: 2021/7/28  15:32
 * @description: com.heyanshu2
 * @java_version: 12.0.2
 */
public class heYanShu {
    static int age;
    String name;
    double height;
    public heYanShu(){

    }
    public heYanShu(String name,double height,int age){
        this.name=name;
        this.age=age;
        this.height=height;
    }
    public static void main(String[] args) {
        heYanShu p1=new heYanShu("xioaming",182,17);     //利用构造器对属性进行赋值
//        p1.age=17;                  //调用方法的形式对属性进行赋值
//        p1.name="xiaohua";
        heYanShu p2=new heYanShu("xiaohua",178,16);
//        p2.age=19;
//        p2.name="xiaoming";
        System.out.println(p1.name);
        System.out.println( p1.age);
        System.out.println(p2.name);
        System.out.println( p2.age);
    }
}

输出结果:静态变量age的值是最后一次所赋的值都为16

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WAD0BhMP-1661865921838)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210728160556712.png)]

4. static 修饰属性总结

  1. static所修饰的属性在类加载的时候一起加入方法区中的静态域中,并赋默认初始值
  2. 先于对象存在,所以在堆中创造的对象里面没有该属性的地址
  3. 访问方式:类名.属性名,对象名.属性名

5. static 修饰方法

  1. public和static 都是修饰词,没有先后顺序所以可以写成:

    public static void main(String[] args){
        
    }
    //或者
    static public void main(Stringp[] args){
        
    }
    
  2. 在静态方法中不能访问非静态属性,(在非静态属性前加上this也不行)因为静态方法先于对象产生,而非静态属性是对象所特有的属性

  3. 在静态方法中不能访问非静态方法,(在非静态方法前加上this 也不行)因为静态方法先于对象(this )产生,非静态方法要用对象去调用,在调用非静态方法的时候可能还没有创建对象

  4. static 修饰的方法只能访问static属性和调用static 方法

  5. 非静态的方法可以用对象名.方法名调用

  6. 静态方法可以使用对象名.方法名或者类名.方法名

    package com.heyanshu3;
    
    /**
     * @author: heYanShu
     * @data: 2021/7/29  14:20
     * @description: com.heyanshu3
     * @java_version: 12.0.2
     */
    public class object1 {           //创建object1类
        static int age;            //创建静态属性age
        String name;
        double weight;
        public object1(){         //创建空构造
    
        }
        public object1(String name,double weight){         //创建构造器的重载,一般不会将静态属性在构造器里面赋值
            this.name=name;//在构造器中对属性进行赋值操作
            this.weight=weight;
        }
        public void a(){                //创建非静态的方法
            System.out.println(age);
            System.out.println(name);
            System.out.println(weight);
        }
        public static void b(){            //创建静态的方法
          //  this.a; //在静态方法中不能调用非静态方法
            System.out.println(age);
         //   System.out.println(name);    //由于在静态方法中调用了非静态属性name,所以报错
          //  System.out.println(this.name);   //在非静态方法中调用了this 关键字所以报错
    
        }
    
        public static void main(String[] args) {
            object1.age=19;
            object1 person=new object1("heyanshu",110);
            object1.b();       //调用静态方法的第一种方式(推荐方法)
            person.b();        //调用静态方法的第二种方式
            person.a();         //调用非静态方法的唯一方式
        }
    }
    
    

    运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43kpFtqY-1661865921838)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210729151521558.png)]

十、代码块

1.代码块的分类

  1. 静态块:静态块是指用static 修饰的代码块,外置在方法外、类里面;里面编写的内容是创建工厂,数据库的初始化信息,而且静态块只在类加载的时候执行一次

    public class test{
        public void a(){
            System.out.println("a------");
        }
        //静态块
        static{
            //内容是创建工厂,数据库的初始化信息
        }
    }
    
  2. 构造块:构造块是指在方法外、类里面的代码块,用于将方法里面的代码拿到方法外面执行

    public class test{
        public void a(){
            System.out.println("a------");
            System.out.println("b------");
            //System.out.println("c------");
        }
        //构造块
        {
           System.out.println("c------");
        }
    }
    
  3. 普通块:放在方法里面的代码块,也就是方法的具体逻辑代码

  4. 同步块(多线程那在详细描述)

2.代码块之间执行的先后顺序

静态块,构造块,构造器,普通块

十一、包和导包

1.包是什么

包就是文件夹,里面可以存放子包和java类文件

2.包的作用

  1. 包的作用就是解决包或者java类文件的重名问题
  2. 解决权限问题

3.怎么导包

  1. 自己创建的包

    • 包名必须是小写英文字母
    • 包名格式:com.公司名.模块名,中间用.来隔开,每一个点代表一个子目录,例如com.heyanshu.test代表的就是在com目录下的heyanshu目录下的test模块(test模块里面就是.java文件)
    • 包名不能是系统关键字,例如nul,com1~com9,con…
    • 声明包的位置在非注释性代码的第一行
    • 导包格式:new 类名;如果设置了自动导包则会自动导入包,如果没用设置就需要手动导包,格式是:import com.公司名.模块名.类名,这句话就是为了定位类名用的
  2. 系统自带的包

    • 导包格式:new 类名
    • 当已经调用了该类,并导入了包,但是想要在其他包里面用同名的类,那么需要自己手动导包
    • 在同一个包下的类可以不用导包,直接用,格式:new 类名
    • 在java.lang包下的类,使用的时候可以不用导包(Math.random就是该包下的方法)、
    • 可以直接导入所有该包里面的所有类,格式;例如impote java.util.*,代表的是将java.util包里面的所有类都导入

4.导包需要注意什么

  • java中的包没有包含和被包含的关系,也就是说当我导入一个包里面的所有类时,在该包下的包含的子包里面的类或者子包并不会导入,如果要用的话,需要自己手动导入,例如:

    import com.heyanshu1.*;     //将该包下的所有类都导入,不包含该包下的子包
    import com.heyanshu1.object1.test1; //这就是上面包的子包,它并没有和上面的包一起导入
    
  • 静态导入:格式:import static java.lang.Math.表示将java.lang下的Math包里面的所有方法导入,如果写成 import java.lang.Math.*表示的是将java包下的lang包下的Math包下的所有类导入

  • 在静态导入后,如果同一个类中有与静态导入的方法相同的方法,那么优先走自己定义的方法

5.代码演示

package com.heyanshu.guide_package_test;

import java.util.Date;
import static java.lang.Math.*;        //j
/**
 * @author: heYanShu
 * @data: 2021/7/29  18:24
 * @description: com.heyanshu.guide_package_test
 * @java_version: 12.0.2
 */
public class test {
    public static void main(String[] args) {
        new Date();
        new java.sql.Date(1000L);
        System.out.println(Math.random());
        System.out.println(Math.PI);
        System.out.println(random());
        System.out.println(PI);
        System.out.println(round(9.9));

    }
    public static int round(double b){
        return 1000;

    }
}

运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPaF0Wba-1661865921839)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210730130406501.png)]

十二、final的使用

1、final修饰变量

package com.heyanshu6;

/**
 * @author: heYanShu
 * @data: 2021/8/6  15:10
 * @description: com.heyanshu6
 * @java_version: 12.0.2
 */
public class attribute {
    public static void main(String[] args) {
        //第一种情况:final修饰基本数据类型的变量
        final int AGE=10;
        //AGE=20;   这里报错因为当被定义的属性变量被final修饰后就不能对其进行修改了,该变量属性就变成了字符常量,一般用大写表示

        //第二种情况:final修饰引用数据类型变量
        final hys p=new hys();        /*内存分析:在对堆中创建的hys类型的对象,通过引用数据类型的p接收该对象的地址,
        通过调用方法m将p传入方法中赋值给形参q,q中现在也是存放的q中的地址,二者都同时指向创建的对象,之后执行方法体,
        重新创建一个hys类型的对象,这是由于p被final修饰所以指向的地址只能是第一个创建的对象,但是q可以改变,
        现在第二个对象创建完后,q将指向创建的对象,地址也变为该对象的地址*/
        m(p);

        //第三种情况:final修饰引用数据类型的变量
        final hys p2=new hys();    //final修饰引用数据类型变量
        n(p2);

    }
    public static void m(hys q){
        q=new hys();             //这里的q的地址可以变化
    }

    //第三种情况:final修饰引用数据类型的变量
    public static void n(final hys q){
        //q=new hys();      这里报错就是因为final修饰了形参q导致其地址值不能更改,必须和输入的引用数据类型的地址一致
    }
}

2. final修饰方法和类

package com.heyanshu6;

/**
 * @author: heYanShu
 * @data: 2021/8/6  15:57
 * @description: com.heyanshu6
 * @java_version: 12.0.2
 */
public final class method {        //当一个类被final修饰,那么就说明该类不能被继承,同时该类中的方法中final也可以省略
    public final void shot(){       //final修饰该方法后,该类的子类中不能对该方法进行重写
        System.out.println("喊叫");
    }
}

package com.heyanshu6;

/**
 * @author: heYanShu
 * @data: 2021/8/6  15:58
 * @description: com.heyanshu6
 * @java_version: 12.0.2
 */
public class chilad extends method {   //这里报错就是因为继承的这个父类被final修饰,那么该父类不能被继承
    @Override
    public void shot() {     //这里报错由于该方法在父类中用final修饰了,所以不能对该方法进行重写
        super.shot();
    }
}

3. Math 类与final修饰符间的联系

  1. Math类属于java.lang包中,使用的时候不需要进行导包处理,直接使用Math.方法名().[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkTs4adI-1661865921840)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806170125771.png)]

  2. Math类中没有子类,不能被继承,就是因为Math类被final修饰了[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EFDAk4w-1661865921841)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806170518111.png)]

  3. Math类里面的属性都被final修饰,变成了大写的字符常量,所以不能被修改,方法其实也都被final修饰了,不过都省略了,因为Math类已经被final修饰了,方法中的final可以省略不写

  4. 外界不可创造对象,因为Math类中的空构造器被private修饰了,该构造器自能在Math类中有效,例如:Math m=new Math()都是报错的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XuyhbLiI-1661865921842)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806171349449.png)]

  5. Math类中的所有方法和属性都被static修饰了,所以不用创建对象就能对里面的属性和方法进行调用,(其实想创建对象也不能创建对象,原因如上第4条),调用格式:类名.方法名()

十三、抽象类和抽象方法

1.抽象类和抽象方法的定义:

当父类中定义的方法无论如何都不能满足子类中的需求时,子类中都必须重写方法才行,那么省去父类中的方法体,用abstract修饰该方法,那么这就构成了一个抽象方法,如果一个类中有抽象方法,那么就必须用abstract修饰该类,这个类就是抽象类,同时抽象类中也可以没有抽象方法。

2.抽象类的继承

抽象类可以被其他类继承,继承的类可以通过abstract修饰成为抽象类,但是一般我们通过在子类中重写所有抽象类的抽象方法而不是用abstract来修饰该子类

3. 抽象类的注意事项

  • 抽象类不可以创建对象,例如如下错误:

    public abstract class person{        //类中有抽象方法必须用abstract来修饰该类,变成一个抽象类
        public abstract void see();      //抽象方法省去方法体用abstract来修饰该方法
        public abstract void play();
    }
    calss student extends person{   //子类继承抽象类必须重写所有所有抽象方法
         public abstract void see(){
             //重写方法体
         }
         public abstract void play(){
             //重写方法体
         }
    }
    class test{
        public void main(String[] args){
            person p=new person();//这里报错因为person类是一个抽象类,不能对他创建对象
            student s=new student();  //在子类中创建对象可以
            s.see();
            s.paly();        
        }
    }
    
  • 子类中可以创建对象

  • 抽象类不可以被final修饰,因为抽象类创建的目的就是为了给子类提供模板的

  • 抽象类中也有构造器,因为在子类中创建对象的时候,会在子类中的构造器第一行执行super,以调用父类中的构造器

4.抽象类和抽象方法的联系

在抽象类中定义抽象方法是为了给子类 提供一个通用的模板,子类可以在此模板基础上进行开发,先重写父类中的抽象方法,然后可以扩展子类的内容,抽象类设计避免了子类设计的随意性,通过抽象类子类设计更加严谨,进行了一定程度上的限制(但是并未限制死,子类中依然可以加入自己的一些东西),使子类更加通用。

5.抽象类不影响多态的写法

任然可以用父类引用指向子类对象:person p=new student();

十四、接口

1.接口的创建

接口是和类同一个层次,不过类用class修饰,接口用interface修饰

public interface mark{     //创建接口
    public static final int NUM=100;
    public static abstract void play();
    public static abstract int age();
}

2. 接口的性质

  • 接口中没有构造器

  • 接口用interface修饰

  • 接口中的属性默认为常量(大写表示),固定修饰符:public static final(可以省略,写了也是灰色字体)

  • 接口中的方法默认为抽象方法,固定修饰符;**public abstract **(可以省略,写了也是灰色字体)

  • 类和接口的关系是:实现关系,用修饰符implements,就是一个class类实现interface接口(可以是多个interface接口)的功能

  • 一个类实现接口必须将接口中的方法(其实是抽象方法)进行重写,实现多少个接口就要对多个接口中的方法全部进行重写,如果

    没有将所有方法进行重写,那么就需要在该类前面用abstract修饰,将其转换为抽象类

    import java.awt.desktop.ScreenSleepEvent;
    
    /**
     * @author: heYanShu
     * @data: 2021/8/7  15:21
     * @description: PACKAGE_NAME
     * @java_version: 12.0.2
     */
    public interface testInterface {     //在接口中默认将属性定义为常量,方法定义为抽象方法,所以修饰词都是灰色
        public static final int NUM=100;   //用final修饰的变量是常量
        public abstract void play();    //用abstract修饰的方法是抽象方法
    }
    interface testInterface2{
        void sleep();
        int age(int age);
    class student extends person implements testInterface,testInterface2{ //student类继承父类person并用implement修饰符来实现接口testInterface和testInterface2
        // 同时必须对接口中的方法进行重写
        @Override
        public void play() {
            System.out.println("我能打篮球");
        }
    
        @Override
        public void sleep() {
            System.out.println("我能睡觉");
        }
    
        @Override
        public int age(int age) {
            return 19;
        }
    
        @Override
        public void see() { //由于父类是个抽象类,所以继承就必须重写父类中的方法
            
        }
    }
    }
    
  • 一个类只能继承一个直接的父类,但是可以实现多个接口,而且继承关系在实现关系之前

    class student extends person implements testInterface,testInterface2{
        
    }
    
  • 接口不能创建对象

  • 接口指向实现类(多态)

    /**
     * @author: heYanShu
     * @data: 2021/8/7  16:59
     * @description: PACKAGE_NAME
     * @java_version: 12.0.2
     */
    public interface test {    //创建接口test
            int AGE=19;
            String date(String date);
            void play();
        }
        class student implements test {   //类student实现接口test
            int age;      //test类中自加的属性
            double weight;
            public String date(String date){   //对接口中的date方法进行重写
                return "2021/8/7";
            }
            public void play(){          //对接口中的方法play进行重写
                System.out.println("我能打羽毛球");
            }
          }
    
    /**
     * @author: heYanShu
     * @data: 2021/8/7  17:13
     * @description: PACKAGE_NAME
     * @java_version: 12.0.2
     */
    public class child {     //创建执行类
        public void play(test t){     //该类中的方法,形式参数是接口类型的变量t,其实传入的是实现接口test的类所创建的对象,这就是接口引用实现类
            t.play();         //这里其实是在调用实现接口的类中的play方法
        }
    }
    
    
    /**
     * @author: heYanShu
     * @data: 2021/8/7  17:10
     * @description: PACKAGE_NAME
     * @java_version: 12.0.2
     */
    public class test1 {
        public static void main(String[] args) {
            test t=new student();    //接口类型的变量t引用实现类创建的对象
            child s=new child();     //创建执行者对象
            s.play(t);   //调用执行者对象中的play对象
        }
    }
    
  • 接口中的常量可以用过接口名.常量名来访问,也可以用实现类.常量名访问,这是因为这些属性都是被static修饰的,所以不需要对象就可以访问,当然也可以通过创建实现类对象,然后用实现类对象.常量名进行访问;还可以通过创建接口引用实现类对象来调用,例如:

    testInterface p=new student();
    System.out.println(p.NUM);
    
  • 接口中有非抽象方法,用public default 来修饰,当在实现类中重写非抽象方法时,不需要加上default这个修饰符;实现类可以通过直接调用非抽象方法的方法名来调用非抽象方法,也可以通过接口名. super.非抽象方法名来调用非抽象方法

  • 接口中有静态方法,用public static来修饰,但是静态方法不可以在实现类中重写,如果重写了,在实现类中也没有重写标志,当在实现类中写了一个和接口中的方法重名的方法的时候,在测试类中调用该方法就会优先调用实现类中的重名方法,若想要调用接口中的方法,就必须用接口名.方法名

  • 接口中之所以加入了非抽象方法,是因为如果接口中只用抽象方法的话,那么当接口中修改内容后,对实现类中的影响较大,需要对修改的方法全部进行重写,如果加入了非抽象方法的话,实现类中不会受影响,想调用就调用。

十五、内部类

1.类的组成

类的组成部分:属性,方法,构造器,代码块(静态块,构造块,普通快,同步块),内部类

2.内部类的组成

内部类由成员内部类和局部内部类组成

3.成员内部类

  1. 成员内部类的位置:方法,构造器,代码块外面,外部内里面,一般只套一层内部类,所以这里的外部类就是我们最开始创建的类

  2. 成员内部类又分为:静态成员内部类非静态成员内部类

  • 非静态成员内部类里面可以访问外部类的属性和方法,特别注意这里的外部类不同于局部内部类
  • 静态成员内部类只能访问外部类中被static修饰的属性和方法
  • 外部类不能直接访问成员内部类中的属性和方法,需要通过在外部类中创建内部类的对象,然后通过该对象来调用内部类的属性和方法
  • 在成员内部类中访问外部类中的重名属性:外部类名.this.重名属性
  • 在内部类中访问内部类中的重名属性:this.重名属性
  • 在内部类中访问内部类中的方法中的重名属性:重名属性,因为系统默认就近原则
  • 静态成员内部类创建对象:外部类名.静态内部类名 对象名=new 外部类名.静态内部类名()
  • 非静态成员内部类中创建对象:先创建外部类的对象a,接着用,外部类名.非静态内部类名 对象名=a.new 非静态内部类名()
  1. 成员内部类里面可以有属性、方法、构造器等
  2. 类修饰符:private,default,protect,pubic ,final,abstract
4.局部内部类
  1. 局部内部类的位置:方法中、构造器、代码块里面

  2. 方法里面的局部内部类中访问的该方法的变量必须是被final修饰的,也就是说不能对该变量进行修改

  3. 用接口当作方法的返回值类型,返回的是具体的实现类的对象;

    p
    

实现类中的影响较大,需要对修改的方法全部进行重写,如果加入了非抽象方法的话,实现类中不会受影响,想调用就调用。

十五、内部类

1.类的组成

类的组成部分:属性,方法,构造器,代码块(静态块,构造块,普通快,同步块),内部类

2.内部类的组成

内部类由成员内部类和局部内部类组成

3.成员内部类

  1. 成员内部类的位置:方法,构造器,代码块外面,外部内里面,一般只套一层内部类,所以这里的外部类就是我们最开始创建的类

  2. 成员内部类又分为:静态成员内部类非静态成员内部类

  • 非静态成员内部类里面可以访问外部类的属性和方法,特别注意这里的外部类不同于局部内部类
  • 静态成员内部类只能访问外部类中被static修饰的属性和方法
  • 外部类不能直接访问成员内部类中的属性和方法,需要通过在外部类中创建内部类的对象,然后通过该对象来调用内部类的属性和方法
  • 在成员内部类中访问外部类中的重名属性:外部类名.this.重名属性
  • 在内部类中访问内部类中的重名属性:this.重名属性
  • 在内部类中访问内部类中的方法中的重名属性:重名属性,因为系统默认就近原则
  • 静态成员内部类创建对象:外部类名.静态内部类名 对象名=new 外部类名.静态内部类名()
  • 非静态成员内部类中创建对象:先创建外部类的对象a,接着用,外部类名.非静态内部类名 对象名=a.new 非静态内部类名()
  1. 成员内部类里面可以有属性、方法、构造器等
  2. 类修饰符:private,default,protect,pubic ,final,abstract
4.局部内部类
  1. 局部内部类的位置:方法中、构造器、代码块里面

  2. 方法里面的局部内部类中访问的该方法的变量必须是被final修饰的,也就是说不能对该变量进行修改

  3. 用接口当作方法的返回值类型,返回的是具体的实现类的对象;

    p
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值