【Java学习笔记】面向对象(持续更新...)

本文详细讲解了类与对象的概念,包括类作为模板,对象实例化的概念,以及成员变量、方法、构造方法和对象实例的创建。通过实例演示,阐述了类与对象的区别、联系以及它们在内存管理中的作用,涉及继承、多态、接口等内容。
摘要由CSDN通过智能技术生成

类与对象:

对于一个项目我们首先看到的是一个个对象,对象是是真实存在的单个个体/东西,基于对象,我们抽出了类,类:即类别,代表一类个体。

所以可以这样说:把类比作是模板,对象就是模板中具体的实例。

类中可以包含:

1、对象的属性/特征----------成员变量

2、对象的行为/动作----------方法

一个类可以创建多个对象

//定义一个学生类(类是同一类别中多个对象的模板)
class Student{
     //成员变量
    String name;
     int  age;
    String address;
    
     //定义study()方法,无返回值,无参数
     void study(){
        System.out.println(name+"在学习");
          }
    
     //定义sayHi()方法,无返回值,无参数
      void sayHi(){
        System.out.println("大家好,我叫"+name+",今年”+age+"岁了,家住"+address);
      }
}
public class StudentTest{

  public static void main(String[] args){
       Student zs = new Student();
   //新建了一个Student类别的对象,对象名zs,它引用的是Student类别中的成员属性及方法
       zs.name = "张三";//给对象zs的成员属性name赋值为“张三”
       zs.age = 25;
       zs.address = "北京";
       zs.study();//调用对象方法
       zs.sayHi();

//点击执行,输出结果为:
     张三在学习
     张三在学习,今年25了,家住北京

//若我们要创建多个对象,用此种方法(对象名.对象属性或方法名)会严重加重我们的代码量,重复代码多
//不是很贴合高质量代码(复用性高)的特点,所以引入了一种构造方法

补充:

类就是数据类型,比如cat类,对象就是一个具体的实例

从猫到对象的说法:(1)创建一个对象 (2)实例化一个对象 (3)把类实例化

                                   这几个说法都是同一个意思

类和对象的区别和联系:类是抽象的,概念的,代表一类事物

                                       对象是具体的,实际的,代表一个具体事物

                                       类是对象的模板,对象是类的一个个体

关于为什么要引入对象的举例:

//单独变量来解决 =>不利于数据的管理(把一只猫的信息拆解了)
//第1只猫信息
String cat1Name = "小白";
int cat1age = 3;
String cat1Color = "白色";

//第2只猫信息
String cat2Name = "小花";
int cat2age = 10;
String cat2Color = "花色";

//数组 ===>(1)数据类型体现不出来
//         (2)只能通过[下标]获取信息,造成变量名字和内容的对应关系不明确
//         (3)不能体现猫的行为
//第1只猫信息
String[] cat1 = {"小白","3","白色"};
String[] cat2 = {"小花","10","花色"};

java内存对象的存在形式

构造方法(constructor):

构造方法也称构造函数、构造器、构建器-------复用给成员变量赋初值代码

1、作用:给成员变量赋初始值

2、与类同名,没有返回值类型(连void都没有)

3、在创建(new)对象时被自动调用

4、若自己不写构造方法,则编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供

5、构造方法可以重载

6、构造方法也属于类中成员,可以用4种访问修饰符来修饰

补充:

构造方法必须与类同名,普通方法也可以与类同名

public class Test {
    Test(){//构造方法
        System.out.println("构造方法");
    }

    void Test(){//无参普通方法
        System.out.println("无参普通方法");
    }

    int Test(int a){//有参普通方法
        return a;
    }

    public static void main(String[] args) {
        Test t = new Test();
        t.Test();
        System.out.println(t.Test(5));
        //System.out.println(t.Test());//编译错误,无参普通方法Test()中没有返回值,
                                       //只有有返回值才能另外用println输出
    }
}
/*
输出:构造方法
     无参普通方法
     5
*/

成员变量与局部变量:

成员变量:写在类中,方法外--------有默认值,可以在整个类中访问

局部变量:写在方法中(包括方法的参数)-------没有默认值,只能在当前方法中使用,在调用方法时,有参需要传参

成员变量能够在类中各个地方调用,而局部变量只能在声明的方法中使用

class Boo{
    int a;
   void show(int b){
     int c;
     System.out.println(a);
     System.out.println(b);
     System.out.println(c);//编译错误,c在使用之前必须先声明并初始化
    }
}
Boo o = new Boo();//在new对象时,a已经有个默认值0
o.show(5);//----b=5,只要调用方法,有参传参


在创建(new)对象时,所有成员变量都会赋默认值

成员变量: 分为两种

1、实例变量:没有static修饰的,属于对象的,存储在堆中,有几个对象就会有几份实例变量,

      通过引用(对象)点来访问

2、静态变量:由static来修饰,属于类的,存储在方法区中,只有一份,通过类名点来访问

成员变量与局部变量时可以重名的:

1、使用的时候默认采取就近原则;

2、当重名时,要区分所赋予的使用范围,用关键字this,this只能用在方法中;

关键字:this

this:指代当前对象,哪个对象调用方法它指的就是哪个对象。

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

public class Student{
      //成员变量:类中定义的,在整个类中
      String name;
      age  int;
      String address;
      //局部变量:方法中定义的,包括参数列表中的变量
      Student(String name1,int age1,String address1){
        name = name1;
        age  = age1;
        address = address1;
      }
}

   //this的应用:
   //刚刚在区分成员变量和局部变量时,Student构造方法中,定义了三个局部变量name1,
   //age1,address1,然后再把这三个变量分别赋给三个局部变量,在实际中,这种赋值复用性不高
   //那么,当局部变量名与成员变量名相同时,此时用下面一种写法:
public class Students{
      String name;
      age  int;
      String address;
     
      Students(String name,int age,String address){
        this.name = name;
        this.age  = age;
        this.address = address;
      }
   //this的默认值:看不见,但系统有默认
   void  sayHi(){
       System.out.println('我叫"+name+",今年"+age+"岁了,家住"+address);
     //此时的三个局部变量name,age,address前面默认有this,但因为无局部变量(也无重名)所以不
     //用this来特别区分这三个变量为成员变量

}
   

内存管理:

内存是由JVM(java虚拟机)来管理的(运行期发生),分为:堆、栈、方法区。

堆:

       存储new出来的对象(该对象包括它的成员变量中的实例变量)

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

       垃圾回收器(GC):不定时到内存中清扫垃圾,回收过程是透明的(看不到的);

                                          并不一定发现垃圾就立刻回收,调用System.gc()可以建议JVM尽快调度

                                          GC来回收

      实例变量的生命周期:创建(new)对象时存储在堆中,对象被回收时一并被回收。

      内存泄漏:不再使用的对象还没有被及时的回收,严重的会导致系统的奔溃。

                        潜艇游戏OutOfBounds()方法也是为了防止内存泄漏。

      建议:当确定对象不再使用时,应及时将引用设置为null

实例一:

 分析:new了一个Bomb对象,存储在堆中,局部变量b1、b2存储在栈中,同时有一个地址,

            当 b2=b1时,会把b1的地址赋给b2

            当b1=null时,b1的地址没了,指向对象的线也就没了,但b1没了,b2还在,地址也还在

             若b2=null时,此时就不能访问Bomb对象

             访问对象必须通过引用,当对象没有指引了,就会成为垃圾,而垃圾就会被GC收走

栈:

       存储正在调用的方法中的局部变量(包括方法的参数)

       调用方法时,会在栈中为该方法分配一块对应的栈帧,栈帧中存储局部变量(包括方法参数)

        方法调用结束时,栈帧被自动清除,局部变量一并被清除。

        方法没有被调用,方法栈帧一定是没有的

       局部变量的生命周期:调用方法时存储在栈中,方法调用结束时与栈帧一并被清除。局部

                                           变量清除,其指向的地址也清除,没有指向的对象会被GC回收。

                                          局部变量中拼接的字面量(str = "hello";str1 = str + "!!!"),若str变量

                                          是main方法中的,str1是普通方法中的变量,那么在普通方法调用完毕

                                           之后,str1拼接的变量也会被GC清除调,而不会放到常量池中。

实例二:

 分析:

          当new了一个Aoo的对象时,Aoo对象包含实例变量a(默认值为0)存储到堆中,并会分配

          一个main方法的栈帧,里面存储局部变量o和地址,在栈中

           一开始栈中没有局部变量b和c,当o.show(8),即调用方法时,会分配show()的栈帧,一旦调完,show()的栈帧自动被清除,程序继续走,一旦main走完,main栈帧也会被清除,main栈帧清除了,指向也就没有了,Aoo对象成为垃圾被收走(main结束,全部清光)

方法区:

       存储.class字节码文件(包括静态变量、所有方法)

       方法只有一份,通过this来区分具体的调用对象

实例三:

分析:

当三块同时出现,先画方法区,方法区先生成.class字节码文件,然后是构造方法及普通方法等

然后在堆中会分配对象

第2个代码:方法区仍然不变,一个类只被加载一次,堆中会再new一个Bomb对象

当调用move()方法时,move也只有一份,方法区中是通过this来区分对象的

补充:

在java中,加载类的时候会自动执行静态块,当创建对象的时候会自动调用构造方法,当有继承类时,一定是先执行超类的而后再执行派生类的

class A{//超类
    static{
        System.out.print("A");
    }
    A(){
        System.out.print("a");
    }
}
class B extends A{//派生类
    static{
        System.out.print("B");
    }
    B(){
        //第一行默认有超类的无参构造方法
        System.out.print("b");
    }
    public static void main(String[] args) {
        A a = new B();
    }
}
/*
输出:ABab
*/

程序执行过程:

1.超类的static块   2.派生类的statec块    3.超类的构造方法    4.派生类的构造方法

内存图(堆、栈):

补充:地址是十六位进制

对象类型:是一种引用类型

                                             栈                                                          堆

内存分析:

1、new了一个Student类型的对象,Student对象及其成员变量存储在“堆”中 。该对象名zs因为在main方法中,属于局部变量,会放到“栈”中,因为对象是一种引用类型,zs会附带一个地址指向Student对象,当修改zs的名字为“李四”,zs会顺着地址1找到Student对象,再将name 中存储的“张三”修改为“李四”

2、同上,ww顺着地址2找到另一个Student对象,再将成员变量age修改为22

8种基本类型(以int类型为实例):

内存分析:

main方法中定义的变量属于局部变量,直接放到“栈”中,因为没有new值,所以堆中没有东西

基本类型数组(以int数组类型为例)

数组是一种引用类型,数组也是一种对象,所以存储在“堆”中,将数组的元素当做成员变量一并存储在“堆”中。

内存分析:

只要new了,就会放到“堆”中,在new的同时,int数组赋予默认值,三个元素i默认值为0,arr数组名在main方法中,局部变量放到“栈”中,并附带一个地址3指向int[]对象的第一个元素

引用类型数组(数组对象):

内存分析:

new了一个Student数组对象,放到“堆”中,默认值看成员变量类型,局部变量stus放到“栈”中,附带地址4指向Student数组对象的第一个元素,new了两个Student对象,数组是一个引用类型,数组stus[0]、stus[1]分别附带地址5、地址6指向各自的数组对象,当修改stus[1]的age时,会先后通过两个地址4和地址6找到Student对象中的age修改为22

 空指针异常(NullPointerException)

演示:

public class Student {
    private String name;
    private int age;
    private String address;
    public Student(String name,int age,String address){
        this.name = name;
        this.age = age;
        this.address =address;
    }
    private void sayHi(){
        System.out.println("大家好,我叫:"+name+",今年:"+age+"岁,家住:"+address);
    }

    public static void main(String[] args) {
        Student[] students = new Student[2];
        students[0] = new Student("张三",19,"廊坊");
        students[0].sayHi();
       //大家好,我叫:张三,今年:19岁,家住:廊坊
        students[0].name = null;//String类型默认值是null,所以也可以赋值null
        students[0].sayHi();
       //大家好,我叫:null,今年:19岁,家住:廊坊

        students[0] = null;//当给一个引用名赋值null时,此时地址就会丢失,形成空指针
        students[0].sayHi();//没有了地址,也就不能调用成员方法
     //Exception in thread "main" java.lang.NullPointerException
    }
}

一个对象的成员属性:若是String类型,它可以被赋值为null

但是对象的引用不可以赋值null,否则就丢失地址,形成空指针,无法访问成员属性及方法

引用类型数组与基本类型数组的区别:

引用类型数组(对象类型数组):1、给数组元素赋值必须new一下

                                                      2、若想访问对象数据必须通过数组元素打点

Student[] stus = new Student[3];
stus[0] = new Stedent("张三",27,"廊坊");
System.out.println(stus[0].age);

继承(extends):

通过extends来实现继承,作用:实现代码的复用性

两个类:

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

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

特点:

1、派生类既能访问自己的,也能访问超类的,但是超类不能访问派生类的

2、一个超类可以有多个派生类,一个派生类只能有一个超类----单一继承

3、具有继承性:父传子,子子相传。

java规定:

1、构造派生类之前必须先构造超类。

2、在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法

                                          若调用了超类的构造方法,则不再默认提供。

补充:

1、继承要符合is(是)的关系,不能为了复用代码就乱继承

2、继承意味着代码虽然我没有写,但也属于我,只是没有写在一起而已

3、继承的是超类中的成员变量和普通方法,而不包括构造方法

4、超类的构造方法时被派生类通过super来调用的

5、子类不能覆盖超类中的final或static方法

class Aoo{
   int a;
 
  Aoo(){}

void show(){}
}

class Boo extends Aoo{
//Boo继承的是Aoo中的成员变量a和普通方法show(),而Aoo中的无参构造方法只能通过Boo的构造方法
//使用关键字过super来调用
}

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

class Aoo{
    Aoo(){
   System.out.println("超类构造方法");
     }     
}

class Boo extends Aoo{
    Boo(){
      //默认第一行:super();
      System.out.println("派生类构造方法");
      }
}

class Test{
  public static void main(String[] args){
     Boo b = new Boo();
    }
}
//输出结果为:
//      超类构造方法
//      派生类构造方法
// 程序从Test类main方法中开始执行,首先new了一个Boo类型的对象,同时调用Boo的无参构造方法,
//程序进入Boo无参构造方法中,因为java规定,派生类继承超类,派生类的构造方法中默认调用超类的
//无参构造方法,且位于派生类构造方法中的第1行,所以先输出“超类构造方法”,再输出“派生类构造方法”


class Coo{
   Coo(int a){
    }
}

class Doo extends Coo{
     Doo(){
      super(5);
      }
}
//当超类定义为有参构造方法时,则不再默认提供super(),super(5)为调用超类有参构造

关键字:super

super:指代当前对象的超类对象

用法:

1、super.成员变量名------------访问超类的成员变量

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

3、super()--------------------调用超类的无参构造方法           

向上造型:

当多种角色干的事情是一样的,可将多个角色的对象造型到超类数组中,统一访问---实现方法复用

1、超类的引用指向派生类的对象

2、规定:能点出来什么,看引用的类型

    new一个超类的对象,能调用超类的成员变量和超类的方法

    new一个派生类的对象,既能调用自己的,也能调用超类的成员变量和方法

    new一个超类类型,派生类的对象,此为向上造型,能点出来看引用的类型里面有什么(超类类型)

class Aoo{
    int a;
   void show{}
}

class Boo extends Aoo{
    int b;
    void test{}
}

class Test{
Aoo aoo = new Aoo();
    aoo.a = 0;
    aoo.show();
    aoo.b = 1;//编译错误,超类不能继承派生类的成员变量
    aoo.test();//编译错误,超类不能继承派生类的方法

Boo boo = new Boo();
    boo.b = 0;
    boo.test();
    boo.a = 1;//派生类可以继承超类的成员变量和普通方法
    boo.show();

Aoo boo1 = new Boo()
    boo1.a = 0;
    boo1.show();
    boo1.b = 1;//编译错误,能点出来的只能是引用类型Aoo的成员变量和方法
    boo1.test();//编译错误
}




若定义了一个超类类型,派生类的对象,因为是超类的类型,那么想访问派生类的方法该用什么办法?这时就用到了方法的重写-------

方法的重写:重新写

1、发生在父子类中,方法名相同,参数列表相同

     ------用在派生类中修改超类(方法)所声明的方法

2、规定:重写方法被调用时,看对象的类型

class Aoo{
   void show(){
  System.out.println("超类方法");
 }
}

class Boo extends Aoo{
    void show(){
   System.out.println("方法重写");
  }
}

class Test{
   Aoo boo = new Boo();
   boo.show();//重写了超类Aoo中show()方法,调用的是Boo中方法名相同,参数类型
               //相同的show()
}
// 输出:方法重写
class Coo extends Aoo{
    void show{
       super.show();//若Coo想在自己方法基础上也想用超类方法,可在第一行加super.方法名()
       System.out.println("方法重写");
    }
}

class Test{
    Aoo coo = new Coo();
    coo.show();//可同时调出超类Aoo方法,也可调自己的方法
}
// 输出:超类方法
//      方法重写    

规则:

 遵循“两同两小一大”原则-------一般都是一模一样的

1、两同:方法名相同,参数列表相同

2、两小:1、派生类方法的返回值类型小于或等于超类方法的

                    void和基本类型时,必须相等

                      引用类型时,小于或等于

                 2、派生类抛出的异常小于或等于超类方法的

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

包名、修饰词

package:声明包

1、避免类的命名冲突

2、同包中的类不能同名,但不同包中的类可以同名

3、包名常常用层次结构(多数开发人员会采用大多域名倒写的方式),建议所有字母都小写,

     Java的包命名不允许以数字开头,但可以以下划线_作为开头

4、包的声明应该在文件的第一行,而且每个Java文件只能有一个包声明

class:声明类

1、在命名主类名称时,须注意大小写,第一个字母须大写,同时主类名称要与文件名称保持一致。

2、类的全称:包名.类名

import:导入类

1、同包中的类可以直接访问

2、不同包中的类不能直接访问,若想访问:

       (1)先import声明类,再访问类------建议

       (2)写类的全称(包名.类名)--------不建议

3、类文件中可以引入任意数量import声明,import声明必须在package包声明后面,类声明之前

访问控制修饰符:保护数据安全

数据(成员变量)私有化(private),行为(方法)大多公开化(public)

1、public(公开的):本类、任何类

2、protected(受保护的):本类、派生类、同包类

3、默认的(没有修饰词default):本类、同包类

4、private(私有的):本类(私有的变量、方法仅可在本类中调用)

注:1、类、接口、抽象类的访问权限只能是public或默认的

        2、类中的成员(包括构造方法)访问权限可以是这4种修饰符

        3、访问权限由高到低:public>protected>默认的>private

        4、私有变量及方法仅可在本类中调用

        5、public权限,其他类文件(无论是否在该文件的包目录下)都可以直接进行调用,

              调用时只需用import关键字引入即可

final

最终的、不可改变的-------单独应用的几率极低

1、修饰变量:变量不能被改变

2、修饰方法:方法不能被重写

3、修饰类:该类不能被继承(但该类可以继承别的类)

static:静态的

静态变量:

1、用static修饰

2、属于类,存储在方法区中,只有一份

3、常常通过类名点来访问

4、何时用:所有对象所共享的数据(图片、音频、视频等)

class Loo{
  int a;
  static int b;

 Loo(){
    a++;
    b++;
  }

 void show(){
  System.out.println("a="+a+",b="+b);
  }
}

public class StaticDemo{
    Loo o1 = new Loo();
    o1.show();
    Loo o2 = new Loo();
    o2.show();
    Loo o3 = new Loo();
    o3.show();
    System.out.println(Loo.b);
}
//输出:a=1,b=1
       a=1,b=2
       a=1,b=3
       b=3

静态成员不会创建对象,只作为类的共享属性进行管理,所有使用了静态成员的地方都共享同一个静态成员 。

内存分析:只要进入了class,就生成.class字节码文件,存放到“方法区”

                  new了一个Loo对象,产生o1地址,此时实例变量a和静态变量b都为0,实例变量属于

                  对象的属性放到“堆中”,而静态变量b放到方法区,然后再调用Loo()构造方法,a+1

                  变为 1,b+1变为1,再通过(o1地址指向)对象名.方法访问show()方法,输出a和b;

                 然后又创建一个新的Loo对象,此时new了一个新的a,但是在后续执行过程中,a始终

                 在新的对象中+1,而b由0被多次修改,最后结果为3。

静态方法:

1、用static修饰

2、属于类,存储在方法区中,只有一份

3、常常通过类名点来访问

4、静态方法中没有this关键字,不能直接访问实例成员(可以访问静态成员)

5、何时用:方法的操作与对象无关

public class Aoo{
          int a;//实例变量,属于对象,存放在堆中,对象点来访问
    static int b;//静态变量,属于类,存放在方法区,类名点来访问

    void show(){
      System.out.println(a);//a为实例变量,方法中默认前面有this,
                            //即this.a指代当前对象的实例变量
      System.out.println(b);//b为静态变量,方法中默认前面有类名Aoo
                            //即Aoo.b
     }

static test(){
      //static修饰的方法,变量名没有隐式this,没有this意味着没有对象,而实例变量需要
      //对象名打点来访问
    //System.out.println(a);//编译错误,没有了隐式this
      System.out.println(b);//前面仍然默认有类名.b
     }
}

public class Boo{
   public static void main(String[] args){
     Aoo.test();//静态的方法,不用new,可直接通过类名.方法名来访问
}
//输出:0
public class Coo{
    int a;

  void show(){//a为实例变量,属于对象,所以show方法不能设计为静态方法
     System.out.println(a);
  }
//plus方法中变量没有与对象有关的,可以用static来修饰
static int plus(int num1,int num2){
     int num = num1 + num2;
     return num;
    }
}
    

静态块:

1、用static修饰

2、属于类,在类被加载期间自动执行,一个类只加载一次,所以静态块只执行一次

3、何时用:加载/初始化静态资源(图片、音频、视频等)

4、可以同时出现多个静态块,按照从上往下的顺序依次执行

class Aoo{
    static{//静态块放到构造方法前后都一样
      System.out.println("静态块");
      }

  Aoo{
     System.out.println("构造方法");
     }
   
}


public class Boo{
   public static void main(String[] args){
      Aoo aoo = new Aoo();
}
//输出:静态块
       构造方法

public class Coo{
   public static void main(String[] args){
      Aoo aoo = new Aoo();
      Aoo aoo1 = new Aoo();
}
//输出:静态块
       构造方法
       构造方法
//由此可得出:静态块在类被加载期间先被执行,且一个类只执行一次静态块
public class Test extends Thread {
    static int x = 10;
    static{
        x += 5;
    }
    public static void main(String[] args) {
        System.out.print("x="+x);
    }
    static{
        x /= 3;
    }
}
//在用到Test类的时候就会将Test.class以及静态变量x加载到方法区中
//同时会自动执行静态块,如果同时出现多个静态块,则按照从上往下的
//顺序依次执行
//初始x为10,增5变为15,后又除以3变为5

static final 常量

1、必须声明同时并初始化

2、常量不能被改变,通过类名点来访问

3、建议:常量名所有字母都大写,多个单词用_来分隔

4、编译器在编译时会将常量直接替换为具体的数,效率高

5、何时用:数据永远不变,并且经常使用

abstract 抽象

抽象方法:

1、由abstract修饰

2、只有方法的定义,没有具体的实现(连{}都没有)

public abstract class Aoo{
   public abstract show();//定义了一个抽象的方法,也必定是抽象类
} 

抽象类:

1、由abstract修饰

2、包含抽象方法的类必须是抽象类

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

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

       (1)重写所有抽象方法----变不完整为完整

       (2)也声明为抽象类------一般不这么用

5、抽象类的意义:

       (1)封装共有的属性和行为------实现代码复用

       (2)为所有派生类提供统一 的类型------向上造型

       (3)可以包含抽象方法,为派生类提供统一的入口(作用是能点出来

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

 成员内部类

局限了访问,应用率低。

1、类中套类,外面的称为外部类,里面的称为内部类

2、内部类通常只服务于外部类,对外不具有可见性

3、内部类对象通常在外部类中创建

4、内部类中可以直接访问外部类的成员(包括私有的)

      内部类中有个隐式的引用指向了创建它的外部类对象:外部名.this

class Mama{
  int a;
void creat(){
   Baby b = new Baby();//内部类对象只能在外部类中创建
   b.show();//调用内部类中show()方法
   b1.show();//放到方法中调用正确
   }
  Baby b1 = new Baby();
   //b1.show();//编译错误,内部类方法不能直接在类中调用
   

class Baby{//内部类
  int b;
  void show(){
     System.out.println(a);//省略写法
     System.out.println(Mama.this.a);//完整写法
   //System.out.println(this.a);//编译错误,this指代当前对象,即Baby,Baby中无变量a
     System.out.println(this.b);//正确
     }
   }
}

class InnerDemo{
  public static void main(String[] args){
     Mama m = new Mama();//创建一个Mama类型对象
   //Baby b = new Baby();//编译错误,内部对象只能在外部类中创建,
                         //对外不具有可见性,不能在外部类外创建

匿名内部类

大大简化了代码

1、若想创建一个类(派生类)的对象,并且对象只被创建一次,可以做成匿名内部类

2、规定:在匿名内部类中默认外面的变量为final的

3、内部类中也有独立的.class文件

     有名内部类:外部类名$内部类名.class

     匿名内部类:外部类名$1.class(后面若再new,数字递增)

class Demo{//做匿名类
  
  //(1)创建了Aoo的一个派生类,但是没有名字(匿名)
  //(2)为该派生类创建了一个对象,对象名是aoo
  //(3)大括号中的为派生类的类体
   Aoo aoo = new Aoo(){//做一个Aoo的匿名类
      void show(){
       System.out.println("重写方法");
    };//因为Aoo类中有抽象方法,所以show()方法必须重写

   Boo boo = new Boo(){做一个Boo的匿名类
    }//Boo类中没有抽象方法,不用重写
 }

abstract class Aoo{
   abstract void show();//有抽象方法
}

abstract class Boo{
}//无抽象方法

隐式的引用

1、this:指代当前对象

2、super:指代当前对象的超类对象

3、外部类.this:指代当前对象的外部类对象

面试题:

1、重写和重载的区别:

  (1)重写(override/overring):发生在父子类中,方法名相同,参数列表相同

                     用在派生类中修改超类(方法)所声明的方法。

  (2)重载(overload/overloading):发生在同一类中(也可以是派生类继承超类的),

            方法名相同,参数列表不同。完全不同的方法,只是方法名正好相同。

2、实例对象与静态变量的区别:

(1)实例对象:属于对象的,在创建对象的时候存储在堆中。

                           创建多少个对象,则实例变量就会在堆中存在多少份

                           通过引用(对象)来访问

(2)静态变量:属于类的,在类被加载期间存储在方法区中,无论创建多少个对象,

                           静态变量 在方法区中都只存在一份

                           通过类名打点来访问

接口

1、是一种引用数据类型

2、由interface定义

3、只能包含常量抽象方法

4、接口不能被实例化(new对象)

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

6、一个类可以实现多个接口,用逗号分隔,若又继承又实现时,应先继承后实现

//接口的语法
interface Inter{
  public static final int NUM = 5;//接口中成员的访问权限只能是public的
  abstract void show();
  int COUNT = 10;//接口中默认前面有public static final
  void test();//接口中默认方法为抽象方法,默认public abstract
  
//int number;//编译错误,接口中默认为常量,必须声明同时初始化
//void say(){}//编译错误,接口中默认抽象方法不能有方法体
}
  
//演示接口继承接口
interface Inter1{
     void show();
 }

interface Inter2 extends Inter1{
    void test();
 }
//接口的实现
class Aoo implements Inter2{
   public void show(){}//抽象方法必须被重写,且访问权限只能是public
   public void test(){}
 }

public class InterfaceDemo{
    public static void main(String[] args){
  //Inter2 inter = new Inter2();//编译错误,接口不能被实例化,
                                //想要实现,必须有实现类,向上造型
    Inter2 aoo1 = new Aoo();//可以造型为它所实现的接口
    Inter1 aoo2 = new Aoo();//向上造型

} 

//接口多实现
interface Inter3{
   void show();
}

interface Inter4{
   void test();
}

abstract class Aoo{
  abstract void say();
}

class Boo extends Aoo implements Inter3,Inter4{//先继承后实现
  public void show(){}
  public void test(){}
  public void say(){}
} 

类和接口的关系

1、类和类-------继承extends

2、接口和接口-------继承extends

3、类和接口-------实现implement

设计规则:

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

2、若对象的行为都一样,设计为普通方法

      若对象的行为不一样,设计为抽象方法

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

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

接口的意义:

1、实现多继承

2、制定了一套标准、规则

多态

意义

1、同一类型的引用指向不同的对象时,有不同的实现------所有抽象方法都是多态的

     -----行为的多态:cut()、getImage()、move()都是多态的

2、同一个对象被造型为不同的类型时,有不同的功能------所有对象都是多态的

     ------对象的多态:我、你、水....

向上造型/自动类型转换

1、超类型的引用指向派生类的对象

2、能点出来什么,看引用的类型

3、能造型成为的数据类型有:超类+所实现的接口

强制类型转化

成功的条件有两种如下:

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

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

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

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

public class Aoo{}

interface Inter{}

public class Coo extends Aoo{}

public class Boo extends Aoo implements Inter{}

public class MultiTypeDemo{
    public static void main(String[] args){
     Aoo o = new Boo();//Aoo的引用o指向了对象Boo
     Boo o1 = (Boo)o;//o引用指向的对象是Boo类型,符合条件1
     Inter o2 = (Inter)o;//o引用指向的对象实现了Inter接口,符合条件2
   //Coo o3 = (Coo)o;//编译错误,o引用指向的对象既不是该类型,也没有继承Coo或实现Coo的接口
                     //会发生ClassCastException类型转换异常
     if(o instanceof Coo){
       Coo o4 = (Coo)o;
      }else{
      System.out.println("o不能强转为Coo类型");
      }
}
//输出:o不能强转为Coo类型

补充:

1、图片存储位置:图片类型有四种:Image、ImageIcon等

    点项目------新建一个目录(Directory)-------命名后将图片全部(ctrl+A)复制点目录名

2、注释创建或消除快捷键:      多行(Ctrl+Shift+/)        单行(Ctrl+/)

   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值