JAVA面向对象

1. 什么是类?什么是对象?

  • 现实生活中是由很多很多对象组成的,基于对象抽出了类

  • 对象:软件中真实存在的单个个体/东西

- 类:类别/类型,代表一类个体
  • 类是对象的模子,对象是类的具体的实例

  • 类中可以包含:

    • 对象的属性/特征-----------------------成员变量
    • 对象的行为/动作-----------------------方法
  • 一个类可以创建多个对象

2. 如何创建类?如何创建对象?如何访问成员?

public class Student { //Student类就是我们自己造的一种引用类型
    //成员变量
    String name;
    int age;
    String address;
    //方法
    void study(){
        System.out.println(name+"在学习...");
    }
    void sayHi(){
        System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
    }
}

public class StudentTest {
    public static void main(String[] args){
        //创建一个学生对象
        Student zs = new Student();
        //给成员变量赋值
        zs.name = "zhangsan";
        zs.age = 25;
        zs.address = "河北廊坊";
        //调用方法
        zs.study();
        zs.sayHi();

        Student ls = new Student();
        ls.name = "lisi";
        ls.age = 24;
        ls.address = "黑龙江佳木斯";
        ls.study();
        ls.sayHi();

        //1)创建了一个学生对象
        //2)给所有成员变量赋默认值
        Student ww = new Student();
        ww.study();
        ww.sayHi();

    }
}

3. 方法的重载(overload/overloading)

------------更加方便用户的访问

  • 发生在同一类或父子类中,方法名相同,参数列表不同
  • 编译器在编译时会根据方法的签名自动绑定方法
//重载的演示
public class OverloadDemo {
    public static void main(String[] args) {
        Aoo o = new Aoo();
        o.show(); //编译器根据方法的签名自动绑定方法
        o.show("zhangsan");
        o.show(25);
        o.show("zhangsan",25);
        o.show(25,"zhangsan");
    }
}

class Aoo{
    void show(){}
    void show(String name){}
    void show(int age){}
    void show(String name,int age){}
    void show(int age,String name){}
    //int show(){ return 1;} //编译错误,重载与返回值类型无关
    //void show(String address){} //编译错误,重载与参数名称无关
}

补充:

  1. 高质量的代码:---------------------以后的目标、拿年薪

    -复用性好、扩展性好、维护性好、可移植性好\健壮性好、可读性好、效率好…

  2. 默认值规则:

    byte,short,int,char------------0
    long---------------------------0L
    double------------------------0.0
    float-------------------------0.0f
    boolean-----------------------false
    引用类型-----------------------null  
    
  3. //若想访问对象,需要通过引用zs
                引用
    数据类型  引用类型变量   指向       对象
    Student     zs         =    new Student(); 
    
  4. 方法的签名:方法名+参数列表

4. 构造方法:构造函数、构造器、构建器

---------------复用给成员变量赋初值代码

  • 作用:给成员变量赋初始值
  • 与类同名,没有返回值类型(连void都没有)
  • 在创建(new)对象时被自动调用
  • 若自己不写构造方法,则编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供(若引用对象的数据可以写死,则可以在new对象时直接传参:Student zs=new Student(“ZS”,20,“LF”))
  • 构造方法可以重载

5. this

---------指代当前对象,哪个对象调用方法它指的就是哪个对象
zs.study()-----------this.指代zs
只能用于实例方法或构造方法中

只能用在方法中,方法中访问成员变量之前默认有个this.

this的用法:

  • this.成员变量名-------------访问成员变量

    成员变量与局部变量同名时,若想访问成员变量则this不能省略

    class Student {
        String name; //成员变量(整个类中)
        int age;
        String address;
        //局部变量(当前方法中)
        Student(String name,int age,String address){
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        void study(){
            System.out.println(name+"在学习...");
        }
        void sayHi(){                       
            System.out.println("大家好,我叫"+name+",今
                               年"+age+"岁了,家住"+address);
            }
        }
    
  • this.方法名()-----------------调用方法(了解)

  • this()---------------------------调用构造方法(了解)

6. null

----------表示空,没有指向任何对象,若引用的值为null,则该引用不能进行任何点操作了,若操作则发生NullPointerException空指针异常
在这里插入图片描述

7. 引用类型数组

1)Bomb[] bs = new Bomb[3];
  bs[0] = new Bomb(100,200); //**1)给元素赋值需要去new个对象**
  bs[1] = new Bomb(200,300);
  bs[2] = new Bomb(220,330);
  //**2)若想访问对象的数据,需要通过数组元素去打点**
  bs[0].x = 111; //给第1个炸弹的x修改为111  
  System.out.println(bs[1].width); //输出第2个炸弹的宽
  bs[2].move(); //第3个炸弹移动
1)Bomb[] bs = new Bomb[3];
  bs[0] = new Bomb(100,200);
  bs[1] = new Bomb(200,300);
  bs[2] = new Bomb(300,400);
  System.out.println(bs[0].width); //输出第1个炸弹的宽
  bs[1].x = 250; //修改第2个炸弹的x为250
  bs[2].move(); //第3个炸弹移动
  
  for(int i=0;i<bs.length;i++){ //遍历所有子弹
      System.out.println(bs[i].height); //输出每个子弹的高
      bs[i].move(); //每个子弹移动
  }
2)Bomb[] bs = new Bomb[]{ //了解
      new Bomb(100,200),
      new Bomb(200,300),
      new Bomb(300,400)
  };

补充:

  1. 成员变量:写在类中,方法外--------有默认值

    局部变量:方法中------------------------没有默认值

  2. java规定:成员变量和局部变量是可以同名的

    使用的时候默认采取的是就近原则

  3. 数组也是一个对象,所以数组对象也存储在堆中,

    将数组的元素当作成员变量一并存储在堆中
    在这里插入图片描述
    在这里插入图片描述

  • 基本类型数组和引用类型数组的区别:
    1.赋值:
    (1)基本类型数组:通过下标直接给元素赋值
    int[] a=new int[3];a[0]=6;
    (2)引用类型数组:要给元素赋值需要去new个对象
    Student[] stus=new Student[10]; stus[0]=new Student(有参传参)
    2.访问:
    (1)基本类型数组:通过下标访问元素
    System.out.println(a[0]);
    (2)引用数组类型:若想访问对象的数据,需要通过数组元素去打点
    System.out.println(stus[0].name);

8. 继承

  • 作用:代码复用

  • 通过extends来实现继承

  • 超类/父类:共有的属性和行为

    派生类/子类:特有的属性和行为

  • 派生类既能访问自己的,也能访问超类的,但超类不能访问派生类的

  • 一个超类可以有多个派生类

    一个派生类只能有一个超类-----------单一继承

  • 具有传递性

  • 继承要符合is a(是一个)的关系

9. super

---------------指代当前对象的超类对象

super的用法:
(只能点出来普通方法)

  • super.成员变量名----------------------访问超类的成员变量(了解)

  • super.方法名()---------------------------调用超类的方法

  • super()-------------------------------------调用超类的构造方

  • java规定:构造派生类之前必须先构造超类

    • 派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
    • 派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供

    super()调用超类构造方法,必须位于派生类构造方法的第一行

    //super的演示
    public class SuperDemo {
        public static void main(String[] args) {
            Boo o = new Boo();
        }
    }
    class Coo{
        Coo(int a){
        }
    }
    class Doo extends Coo{
        Doo(){
            super(5); //调用超类的有参构造
        }
        /*
        //如下代码为默认的:
        Doo(){
            super();
        }
         */
    }
    
    class Aoo{
        Aoo(){
            System.out.println("超类构造");
        }
    }
    class Boo extends Aoo{
        Boo(){
            //super(); //默认的,调用超类的无参构造
            System.out.println("派生类构造");
        }
    }
    

10. 向上造型

---------------------代码复用

  • 超类型的引用指向了派生类的对象
  • 能点出来什么,看引用的类型
package ooday03;
//向上造型的演示
public class UploadDemo {
    public static void main(String[] args) {
        Eoo o1 = new Eoo();
        o1.a = 1;
        o1.show();
        //o1.b = 2;  //编译错误
        //o1.test(); //编译错误,超类不能访问派生类的

        Foo o2 = new Foo();
        o2.b = 1;
        o2.test();
        o2.a = 2;  //正确
        o2.show(); //正确,派生类可以访问超类的

        Eoo o3 = new Foo(); //向上造型
        o3.a = 1;
        o3.show();
        //o3.b = 2;  //编译错误
        //o3.test(); //编译错误,能点出来什么,看引用的类型
    }
}

class Eoo{
    int a;
    void show(){
    }
}
class Foo extends Eoo{
    int b;
    void test(){
    }
}

补充:

  1. 继承意味着代码虽然我没有写,但也属于我,只是没有写在一起而已
  2. 泛化:将共有的抽出来的过程,泛化是设计层面的概念,从代码实现层面来说咱们就是继承,泛化就是继承

11. 方法的重写(override/overriding)

重新写、覆盖

  • 发生在父子类中,方法名相同,参数列表相同
  • 重写方法被调用时,看对象的类型
  • 派生类不能重写超类中的static方法

当派生类觉得超类的行为不够好时,可以重写

我继承了一个中餐馆
class Aoo{
    void do(){
        做中餐
    }
}
A:我还是想做中餐------------不需要重写
    class Boo extends Aoo{
    }
B:我想改做西餐--------------需要重写
    class Boo extends Aoo{
        void do(){
        	做西餐
    	}
    }
C:我想在中餐基础之上加西餐-----需要重写(super中餐,再加入西餐)
    class Boo extends Aoo{
        void do(){
        	super.do();
            做西餐
    	}
    }

12. 重写与重载的区别

  • 重写:发生在父子类中,方法名相同,参数列表相同

    一般用于在派生类中修改超类的方法

  • 重载:发生在同一类中,方法名相同,参数列表不同

    是完全不同的方法,只是方法名相同而已

13. package和import

  • package:声明包

    • 作用:避免类的命名冲突
    • 同包中的类不能同名,不同包中的类可以同名
    • 类的全称:包名.类名,包名常常有层次结构
    • 建议:包名所有字母都小写

    说明:package声明包必须位于第一行

  • import:导入类

    • 同包中的类可以直接访问,不同包的类不能直接访问,若想访问:
      • 先import导入类,再访问类----------建议
      • 类的全称-----------------------------------太繁琐,不建议

    说明:import导入类必须位于声明包的下一行

14. 访问控制修饰符

封装的意义:隐藏一些东西,暴露一些东西,来保护数据的安全

  • public:公开的,任何类-------(方法)
  • protected:受保护的,本类、同包类、派生类
  • 默认的:什么也不写,本类、同包类
  • private:私有的,本类--------(成员变量)
  1. 类的访问权限只能是public或默认的
  1. 类中成员的访问权限如上四种都可以
//封装的意义
class Card{
    private String cardId;
    private String cardPwd;
    private double balance;
    
    public boolean payMoney(double money){ //支付金额
        if(balance>=money){
            balance-=money;
            return true;
        }else{
            return false;
        }
    }
    
    public boolean checkPwd(String pwd){ //检测密码
        if(pwd与cardPwd相同){
            return true;
        }else{
            return false;
        }
    }
}
//访问权限范围:
package ooday04;
//演示访问控制修饰符
public class Aoo {
    public int a;     //任何类
    protected int b;  //本类、派生类、同包类
    int c;            //本类、同包类
    private int d;    //本类

    void show(){
        a = 1;
        b = 2;
        c = 3;
        d = 4;
    }
}

class Boo{ //---------------演示private
    void show(){
        Aoo o = new Aoo();
        o.a = 1;
        o.b = 2;
        o.c = 3;
        //o.d = 4; //编译错误
    }
}

package ooday04_vis;
import ooday04.Aoo;
public class Coo { //演示同包的概念
    void show(){
        Aoo o = new Aoo();
        o.a = 1;
        //o.b = 2; //编译错误
        //o.c = 3; //编译错误
        //o.d = 4; //编译错误
    }
}

class Doo extends Aoo{ //演示protected
    void show(){
        a = 1;
        b = 2;
        //c = 3; //编译错误
        //d = 4; //编译错误
    }
}

15. static:静态的

  • 静态变量:

    • 由static修饰
    • 属于类,存储在方法区中,只有一份
    • 常常通过类名点来访问,也可以通过对象名打点来使用
    • 何时用:所有对象所共享的数据(图片、音频、视频等)
    public class StaticDemo {
        public static void main(String[] args) {
            Eoo o1 = new Eoo();
            o1.show();
            Eoo o2 = new Eoo();
            o2.show();
            Eoo o3 = new Eoo();
            o3.show();
            System.out.println(Eoo.b); //常常通过类名点来访问
        }
    }
    
    class Eoo{ //演示静态变量
        int a;
        static int b;
        Eoo(){
            a++;
            b++;
        }
        void show(){
            System.out.println("a="+a+",b="+b);
        }
    }
    

    在这里插入图片描述

  • 静态方法:

    • 由static修饰
    • 属于类,存储在方法区中,只有一份
    • 常常通过类名点来访问,也可以通过对象名打点来使用
    • 静态方法没有隐式this传递,所以不能直接访问实例成员
    • 何时用:方法的操作与对象无关
    //static的演示
    public class StaticDemo {
        public static void main(String[] args) {
            Goo.plus(4,6);
        }
    }
    
    //演示静态方法
    class Foo{
        int a; //实例变量(由对象来访问)
        static int b; //静态变量(由类名来访问)
    
        void show(){ //有隐式this
            System.out.println(this.a);
            System.out.println(Foo.b);
        }
        static void test(){
            //静态方法中没有隐式this传递
            //没有this就意味着没有对象
            //而实例变量a是必须由对象来访问的
            //所以下面的语句发生编译错误
            //System.out.println(a); //编译错误
    
            System.out.println(Eoo.b);
        }
    }
    
    //演示静态方法何时用
    class Goo{
        int a; //对象的属性
        //方法中用到了对象的属性a,意味着show()的操作与对象是有关的,不能做成静态方法
        void show(){
            System.out.println(a);
        }
        //方法中没有用到对象的属性和行为,意味着plus()的操作与对象是无关的,可以做成静态方法
        static void plus(int num1,int num2){
            int num = num1+num2;
            System.out.println(num);
        }
    }
    
  • 静态块:

    • 由static修饰
    • 属于类,在类被加载期间自动执行,一个类只被加载一次,所以静态块也只执行一次
    • 何时用:初始化/加载静态资源(图片、音频、视频等)
    public class StaticDemo {
        public static void main(String[] args) {
            Hoo o4 = new Hoo();
            Hoo o5 = new Hoo();
            Hoo o6 = new Hoo();
        }
    }
    //演示静态块
    class Hoo{
        static {
            System.out.println("静态块");
        }
        Hoo(){
            System.out.println("构造方法");
        }
    }
    

    补充:

  • 在构造方法中给实例变量做初始化

  • 在静态块中给静态变量做初始化

执行顺序:父类静态块–>子类静态块–>父类非静态块–>父类构造方法–>子类非静态块–>子类构造方法

16.重写方法原则-------两同、两小、一大

两同:方法名名和参数列表相同

两小:

  • 派生类方法抛出异常必须小于或等于超类;
  • 派生类方法的返回值类型必须小于或等于超类;
    void/基本类型:必须相等
    引用类型:必须小于或等于

一大: 派生类方法的访问权限必须大于或等于超类

补充:

  1. 成员变量分两种:
  • 实例变量:没有static修饰,属于对象的,存储在堆中,

    ​ 有几个对象就有几份,通过引用打点来访问

  • 静态变量:有static修饰,属于类的,存储在方法区中,

    ​ 只有一份,通过类名打点来访问

17. final:最终的,不可改变的

----------单独应用几率低

  • 修饰变量:变量不能被改变

    //演示final修饰变量
    class Aoo{
        final int num = 5;
        void show(){
            //num = 55; //编译错误,final的变量不能被改变
        }
    }
    
  • 修饰方法:方法不能被重写

    //演示final修饰方法
    class Boo{
        final void show(){}
    }
    class Coo extends Boo{
        //void show(){} //编译错误,final修饰的方法不能被重写
    }
    
  • 修饰类:类不能被继承

    //演示final修饰类
    final class Doo{}
    //class Eoo extends Doo{} //编译错误,final的类不能被继承
    class Foo{}
    final class Goo extends Foo{} //不能当老爸,但能当儿子
    

18. static final常量

---------------应用率高

  • 必须声明同时初始化
  • 通过类名点来访问,不能被改变
  • 建议:常量名所有字母都大写,多个单词用_分隔
  • 编译器在编译时会将常量直接替换为具体的值,效率高
  • 何时用:数据永远不变,并且经常使用
public class StaticFinalDemo {
    public static void main(String[] args) {
        System.out.println(Hoo.PI); //通过类名点来访问
        //Hoo.PI = 3.1415926; //编译错误,常量不能被改变

        //1)加载Ioo.class到方法区中
        //2)将静态变量num一并存储到方法区中
        //3)到方法区中获取num的值并输出
        System.out.println(Ioo.num);

        //编译器在编译时将常量直接替换为具体的值,效率高
        //相当于System.out.println(5);
        System.out.println(Ioo.COUNT);
    }
}

class Ioo{
    public static int num = 5; //静态变量
    public static final int COUNT = 5; //常量
}

class Hoo{
    public static final double PI = 3.14159;
    //public static final int NUM; //编译错误,常量必须声明同时初始化
}

19. 抽象方法

  • 由abstract修饰
  • 只有方法的定义,没有具体的实现(连{}都没有)

抽象类:

  • 由abstract修饰

  • 包含抽象方法的类必须是抽象类

  • 抽象类不能被实例化(new对象)

  • 抽象类是需要被继承的,派生类:

    • 重写所有抽象方法--------------变不完整为完整
    • 也声明为抽象类------------------一般不这么做

抽象类的意义:

  • 封装共有的属性和行为--------------------代码复用

  • 为所有派生类提供统一的类型-----------向上造型—代码复用

  • 可以包含抽象方法,为所有派生类提供统一的入口(能点出来)

    派生类的行为不同,但入口是一致的,同时相当于定义了一个标准

补充:

抽象方法/抽象类的疑问:

  • 抽象方法的存在意义是什么?

    • 保证当发生向上造型时,通过超类型的引用能点出来那个方法
  • 既然意义只在于能点出来,那为什么不设计为普通方法?

    • 若设计为普通方法,则派生类可以重写也可以不重写,而设计为抽象方法,可以强制派生类必须重写------做了个标准,强制必须重写

20.成员内部类

------------应用率低,了解

  • 类中套类,外面的称为外部类,里面的称为内部类
  • 内部类通常只服务于外部类,对外不具备可见性
  • 内部类对象只能在外部类中创建
  • 内部类中可以直接访问外部类的成员(包括私有的),在内部类中有个隐式的引用指向了创建它的外部类对象------外部类名.this
public class InnerClassDemo {
    public static void main(String[] args) {
        Mama m = new Mama();
        //Baby b = new Baby(); //编译错误,内部类对外不具备可见性
    }
}

class Mama{ //外部类
    private String name;
    Baby b = new Baby(); //内部类对象通常在外部类中创建
    class Baby{ //内部类
        void show(){
            System.out.println(name);
            System.out.println(Mama.this.name); //Mama.this指代它的外部类对象
        }
    }
}

21. 匿名内部类

  • 若想创建一个类的派生类对象,并且对象只创建一个(一次),此时该类(派生类)不必命名,称为匿名内部类
    - 匿名内部类中不能修改外面变量的值,也不能访问在外面被修改过的变量,因为在此处该变量默认为final的
 public class AnonInnerClassDemo {
     public static void main(String[] args) {
         //1)创建了Aoo的一个派生类,但是没有名字
         //2)为该派生类创建了一个对象,名为o1
         //3)大括号中的为派生类的类体
         Aoo o1 = new Aoo(){
         };
 
         //1)创建了Aoo的一个派生类,但是没有名字
         //2)为该派生类创建了一个对象,名为o2
         //3)大括号中的为派生类的类体
         Aoo o2 = new Aoo(){
         };
 
 
         int num = 5;
         num = 55;
         //1)创建了Boo的一个派生类,但是没有名字
         //2)为该派生类创建了一个对象,名为o3
         //3)大括号中的为派生类的类体
         Boo o3 = new Boo(){
             void show(){
                 System.out.println("showshow");
                 //num = 66; //编译错误,匿名内部类中不能修饰外面变量的值,因为在此处默认为final的
             }
         };
         o3.show();
     }
 }
 
 abstract class Boo{
     abstract void show();
 }
 
 abstract class Aoo{
 }

补充:

  • 隐式对象:

    • this:当前对象
    • super:当前对象的超类对象
    • 外部类名.this:当前对象的外部类对象
    • 匿名内部类不能修改外面变量的值,因为在此处默认为final的
  • 小面试题:

    • 问:内部类有独立的.class字节码文件吗?

      答:有

  • 做功能的套路:

    • 先写行为/方法:
      • 若为某对象所特有的行为,就将方法设计在特定的类中
      • 若为所有对象所共有的行为,就将方法设计在超类中
    • 窗口调用:
      • 若为定时发生的,就在定时器中调用
      • 若为事件触发的,就在侦听器中调用----------明天上午讲
  • 调错方式:

    • 打桩:System.out.println(数据);

22. 接口

  • 是一种引用数据类型

  • 由interface定义

  • 只能包含常量和抽象方法------默认权限是public

  • 接口不能被实例化

  • 接口是需要被实现/继承,实现/派生类:必须重写所有抽象方法

  • 一个类可以实现多个接口,用逗号分隔,

    若又继承又实现时,应先继承后实现

  • 接口可以继承接口

  • 接口的意义:

    • 封装部分派生类共有的属性和行为,实现多继承
    • 制定了一个标准,一种规范
  public class InterfaceDemo {
      public static void main(String[] args) {
          //Inter o = new Inter(); //编译错误,接口不能被实例化
          Inter5 o1 = new Doo(); //向上造型
          Inter4 o2 = new Doo(); //向上造型
      }
  }
  
  //演示接口的定义
  interface Inter{
      public static final int NUM = 5;
      public abstract void show();
      int COUNT = 5; //默认public static final   //接口中的成员默认访问权限是public
      void test(); //默认public abstract
      //int number; //编译错误,常量必须声明同时初始化
      //void say(){} //编译错误,抽象方法不能有方法体
  }
  
  //演示接口的定义
  interface Inter{
      public static final int NUM = 5;
      public abstract void show();
      int COUNT = 5; //默认public static final   //接口中的成员默认访问权限是public
      void test(); //默认public abstract
      //int number; //编译错误,常量必须声明同时初始化
      //void say(){} //编译错误,抽象方法不能有方法体
  }
  
  //演示接口的实现
  interface Inter1{
      void show();
      void test();
  }
  class Aoo implements Inter1{
      public void show(){} //重写接口中的抽象方法时,访问权限必须设计为public的
      public void test(){}
  }
  
  //演示接口的多实现
  interface Inter2{
      void show();
  }
  interface Inter3{
      void test();
  }
  abstract class Boo{
      abstract void say();
  }
  class Coo extends Boo implements Inter2,Inter3{
      public void show(){}
      public void test(){}
      void say(){}
  }
  
  //演示接口继承接口
  interface Inter4{
      void show();
  }
  interface Inter5 extends Inter4{
      void test();
  }
  class Doo implements Inter5{
      public void test(){}
      public void show(){}
  }

补充:

  1. 类和类------------------------继承extends

    接口和接口------------------继承extends

    类和接口---------------------实现implements

  2. 设计规则:

    • 将所有派生类所共有的属性和行为,抽到超类中-------------抽共性

    • 派生类的行为都一样,则设计为普通方法

      派生类的行为不一样,则设计为抽象方法

    • 将部分派生类所共有的属性和行为,抽到接口中

      接口是对继承的单根性的扩展---------------实现多继承

      符合既是也是原则时,应使用接口

  3. 可以向上造型为:超类+所实现的接口

23. 多态

表现:

  • 同一个对象被造型为不同的类型时,有不同的功能

    – 对象的多态:我、你、水…------所有对象都是多态的

  • 同一类型的引用指向不同的对象时,有不同的实现

    –行为的多态:cut(),move(),getImage()–所有抽象方法都是多态的

  • 向上造型/自动类型转换:--------------------代码复用

    • 超类型的引用指向派生类的对象
    • 能点出来什么,看引用的类型
    • 能造型成为的数据类型有:超类+所实现的接口
  • 强制类型转换,成功的条件只有如下两种:

    • 引用所指向的对象,就是该类型

    • 引用所指向的对象,实现了该接口或继承了该类

  • 强转时若不符合如上条件,则发生ClassCastException类型转换异常

    建议:在强转之前先通过instanceof来判断引用的对象是否是该类型

 public class MultiTypeDemo {
     public static void main(String[] args) {
         Aoo o = new Boo();
         Boo o1 = (Boo)o;     //引用o所指向的对象,就是Boo类型
         Inter o2 = (Inter)o; //引用o所指向的对象,实现了Inter接口
         //Coo o3 = (Coo)o; //运行时ClassCastException类型转换异常
         if(o instanceof Coo){ //false
             Coo o4 = (Coo)o;
         }else{
             System.out.println("o不是Coo类型");
         }
         /*
         System.out.println(o instanceof Boo);   //true
         System.out.println(o instanceof Inter); //true
         System.out.println(o instanceof Coo);   //false
          */
     }
 }
 
 interface Inter{ }
 class Aoo{ }
 class Boo extends Aoo implements Inter{ }
 class Coo extends Aoo{ }

补充:

  1. 接口可以继承多个接口:

    interface Inter1{
        void show();
    }
    interface Inter2{
        void test();
    }
    interface Inter3 extends Inter1,Inter2{
        void say();
    } 
    
  2. 何时需要强转?

    想访问的属性/行为在超类中没有,必须强转,强转之前先instanceof判断

  3. ArrayIndexOutOfBoundsException:数组下标越界异常

    NullPointerException:空指针异常

    ClassCastException:类型转换异常

    4.碰撞检测
    在这里插入图片描述

24.内存管理:由JVM管理的

  • 堆:

    • 存储new出来的对象(包括实例变量)

    • 垃圾:没有任何引用所指向的对象

      垃圾回收器(GC)不定时到内存堆中清扫垃圾,回收的过程中透明的(看不到的),不一定一发现垃圾就立刻回收,通过调用System.gc()建议虚拟机尽快调度GC来回收

    • 实例变量的生命周期:

      ​ 创建对象时存储在堆中,对象被回收时一并被回收

    • 内存泄漏:不再使用的对象没有被及时的回收,严重的泄漏会导致系统的崩溃,建议:不再使用的对象应及时将引用设置为null

在这里插入图片描述
在这里插入图片描述

  • 栈:

    • 存储正在调用的方法中的局部变量(包括方法的参数)
      (如果局部变量为基本类型,则栈中的局部变量存储数字;如果局部变量为引用类型,则栈中的局部变量存储地址)

    • 调用方法时,会为该方法在栈中分配一块对应的栈帧,栈帧中存储局部变量(包括方法的参数),方法调用结束时,栈帧被自动清除,局部变量一并被清除。

    • 局部变量的生命周期:

      ​ 调用方法时存储在栈中,方法调用结束时与栈帧一并被清除

在这里插入图片描述

  • 方法区:

    • 存储.class字节码文件(包括静态变量、所有方法)
    • 方法只有一份,通过this来区分具体的调用对象

在这里插入图片描述

25.面向对象三大特征总结

1.封装:

  • 类:封装对象的属性和行为
    - 方法:封装的是具体的业务逻辑实现
    • 访问控制修饰符:封装的是具体的访问权限

2.继承:

  • 作用:代码复用

  • 超类:所有派生类所共有的属性和行为

    接口:部分派生类所共有的属性和行为

    派生/实现类:派生类所特有的属性和行为

  • 单一继承、多接口实现,具有传递性

3 多态:

  • 行为多态:所有抽象方法都是多态的(通过重写来表现)

  • 对象多态:所有对象都是多态的(通过向上造型为表现)

- 重写、向上造型、强制类型转换(instanceof判断)

26.补充

  1. 实例变量和局部变量的区别:
  • 实例变量:
    • 写在类中、方法外
    • 创建对象时存储在堆中,对象被回收时一并被回收
    • 有默认值
  • 局部变量:
    • 写在方法中
    • 调用方法时存储在栈中,方法调用结束时与栈帧一并被清除
    • 没有默认值
Aoo o = new Aoo();-------------a=0
o.show(5);---------------------b=5

class Aoo{
    int a;
    void show(int b){
        int c;
        System.out.println(a); //0
        System.out.println(b); //5
        System.out.println(c); //发生编译错误
    }
}

2.面试题:

  • 问:java是值传递还是引用传递?
  • 答:java只有值传递,基本类型传递的是具体的数,引用类型传递的是具体的地址

3.文档注释:

  • 为功能性注释,只在三个地方使用,分别是类上、方法上和常量上
//文档注释是功能性注释,只在三个地方使用,分别是类上、方法上和常量上
/**
 * 在类上使用时用于说明当前类的设计目的和整体功能介绍
 * 例如: 此类用于演示java文档注释
 *
 * @author 作者WKJ
 */
public class ApiDocDemo {
    /**
     * sayHi方法中使用的问候语
     */
    public static final String INFO = "你好!";

    /**
     * 为指定用户添加问候语
     * @param name 指定用户的名字
     * @return 含有问候语的字符串
     */
    public String sayHi(String name){
        return INFO+name;
    }
}
  1. getter/setter:

    class Student{
        private String name;
        private int age;
    
        public String getName(){ //getter获取
            return name;
        }
        public void setName(String name){ //setter设置
            this.name = name;
        }
        public int getAge(){ //getter获取
            return age;
        }
        public void setAge(int age){ //setter设置
            this.age = age;
        }
    }
    
    //getter和setter的演示
    public class GetterSetterDemo {
        public static void main(String[] args) {
            Student zs = new Student();
            zs.setName("zhangsan");
            zs.setAge(25);
            System.out.println(zs.getName());
            System.out.println(zs.getAge());
    
            Student ls = new Student();
            ls.setName("lisi");
            ls.setAge(24);
            System.out.println(ls.getName());
            System.out.println(ls.getAge());
        }
    }
    

5.引用类型赋值
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在雪山吃火锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值