JavaSE进阶 | import、访问控制权限、Object、匿名内部类

目录

🏀面向对象

🥅package和import

🥅访问控制权限修饰符

🥅Object类

🥅匿名内部类


🏀面向对象

🥅package和import

❤️package

1、为什么要使用package?

    package是java中包机制,包机制的作用是为了方便程序的管理;

    不同功能的类分别存放在不同的包下(按照功能划分的,不同软件包具有不同的功能)

2、package是怎么用的?

    package是一个关键字,后面加包名;例如:package com.dlu.javase.day01

    注意:package语句只允许出现在java源代码的第一行

3、包名的命名规范?

    一般采用公司域名倒叙的方式(因为公司域名具有全球唯一性)

    包名命名规范:公司域名倒序+/名+模块名+功能名

4、对于带有package的java程序怎么编译?怎么运行?

   ⭐️以文本编译器为例:

   1、编译javac -d . PackageTest01

       -d表示带包编译

       .表示编译之后生成的class文件放到当前目录下

   2、运行

        java com.dlu.javase.day01.PackageTest01

   3、解释:实际上在PackageTest01.java文件目录下会生成com文件夹---》com文件夹下生成dlu文件夹---》dlu文件夹下生成javase文件夹---》javase文件夹下生成day01文件夹---》day01文件夹下生成PackageTest01.class文件。运行时还是在PackageTest01.java文件目录下执行:java com.dlu.javase.day01.PackageTest01即可!

  ⭐️IDEA编译器为例:

    1、先创建包(Package);和创建类的时候步骤一致

    2、创建包之后,在包下面再创建类,生成的类就会自动带上package com.dlu.javase.day01;然后直接运行就行

package com.dlu.javase.day01;
public class PackageTest01 {
    public static void main(String[] args) {
        System.out.println("HelloWorld");
    }
}

❤️import

两个类包名相同(包名能省略)。

两个类包名不同(包名不能省略,可以用import进行导包)。

⭐例1:两个类包名相同

package com.dlu.javase.day01; //包名与PackageTest01包名相同

public class Test01{
	public static void main(String[] args){
		// 创建PackageTest01对象
		//PackageTest01的完整类名是:com.dlu.javase.day01.PackageTest01(这是带包的情况下类名)
		com.dlu.javase.day01.PackageTest01 hw = new com.dlu.javase.day01.PackageTest01();
		System.out.println(hw);//com.dlu.javase.day01.PackageTest01@15db9742

		//包名省略?---也没问题
		//这里的包名之所以可以省略,是因为PackageTest01和Test01在同一个Package(包)下
		PackageTest01 hw1 = new PackageTest01();
		System.out.println(hw1);//com.dlu.javase.day01.PackageTest01@6d06d69c
	}
}

⭐例2:两个类包名不同

1、import什么时候使用?例如:A类中使用B类:
        A和B类都在同一个包下;不需要import!
        A和B类不在同一个包下;需要使用import!

       默认java.lang.*;这个包下的类(直接子类)都不需要使用import导入     

2、import怎么用?
        import语句只能出现在package语句下,class声明语句之前。
        import语句也可以采用星号(*)的方式,星号省略的是当前类名,不能多省略

package com; //包名与PackageTest01包名不相同

//import com.dlu.javase.day01.PackageTest01;//导入需要的包
import com.dlu.javase.day01.*;//采用星号的方式也是可以的,省略类名

public class Test02{
	public static void main(String[] args){
		// 创建PackageTest01对象
		com.dlu.javase.day01.PackageTest01 hw = new com.dlu.javase.day01.PackageTest01();
		System.out.println(hw);//com.dlu.javase.day01.PackageTest01@15db9742

		//这里包名就不能省略:
		/*
		  Test02在com包下
		  PackageTest01在com.dlu.javase.day01下
		  不在同一个包下,包名不能省略
		*/
		/*
		但是我们每次创建PackageTest01对象又很麻烦,那么长的类名;所以这就需要import
		PackageTest01 hw1 = new PackageTest01();
		System.out.println(hw1); //err
		*/

		//import com.dlu.javase.day01.PackageTest01导入包以后,就可以省略包了
		PackageTest01 hw2 = new PackageTest01();
		System.out.println(hw2);//com.dlu.javase.day01.PackageTest01@6d06d69c
	}
}

❤️解释遗留问题Scanner

(1)s.next表示读取一个字符串String类型,但是一次只能读一个连续的字符串,遇到空格就会中止;s.nextLine()表示一行一行的读,空格也能读取

(2)例如:Hello World前者只能那个读取到Hello遇到空格就会中止;后者可以把Hello World都可以读取出来。

package com.dlu.javase.day01;
import java.util.Scanner;//导包
//import java.util.*;//也可以

public class Test03{
	public static void main(String[] args){
		//为什么这样写?
		//Test03类和Scanner类不在同一个包下;java.util就是Scanner的包名
		//java.util.Scanner s = new java.util.Scanner(System.in);

		//import导包的形式
		Scanner s = new Scanner(System.in);

		String str = s.next();
		System.out.println("您输入的字符串是:"+str);

		//String为什么不需要导包呢?
		//因为在lang包下的直接之类都不要导入(在比如:System)
		java.lang.String name = "张三";
		String username = "李四";
		System.out.println(name);
		System.out.println(username);
	}
}

❤️总结:

以文本编译器为例,重点掌握原理;IDEA中直接使用和编译就行很方便。

⭐package(对于文本编译器)

第一:package出现在java源文件第一行。
第二:带有包名怎么编译?javac -d. xxx.java
第三:怎么运行?java 完整类名(带包名)
补充:以后说类名的时候,如果带着包名描述,表示完整类名;如果没有带包,描述的话,表示简类名。例如:
(1)java.util.Scanner 完整类名(全限定类名)。
(2)Scanner 简类名。

⭐import(对于文本编译器)

1、import什么时候不需要?
java.lang下的不需要,同包下不需要;其它一律都需要!

2、怎么用?
(1)import 完整类名;

         import java.util.Scanner;  完整类名。

(2)或者import 包名.*

         import java.util.*;

         编译器在编译的时候,会自动把*变成具体的类名

(3)想省但也不能太省了,例如:import java.*;这是不允许的,因为在java语言中规定,这里的*只代表某些类的名字

3、不同包名下的相同类名不会冲突;例如:org.Test和com.Test不会冲突;类名相同就通过包名来区分!

🥅访问控制权限修饰符

访问控制权限都有哪些?4个

private       私有

protected   受保护
public        公开
默认(什么都没有)

以上的4个访问控制权限:控制的范围是什么?

(1)private 表示私有的,只能在本类中访问

(2)protected表示只能在本类、子类、同包中访问。

(3)public 表示公开的,在任何位置都可以访问
(4)
“默认”表示只能在本类、同包下访问。     

   访问控制修饰符       本类            同包            子类            任意位置
 ---------------------------------------------------------------------------
   public              可以            可以            可以            可以
   protected           可以            可以            可以            不行
   默认                可以            可以            不行            不行
   private             可以            不行            不行            不行

范围从大到小排序:public(4) > protected(3) > 默认(2) > private(1)

访问控制权限修饰符可以修饰什么?
属性 和 方法(4个都能用)
类 和 接口(public和默认能用,其它不行)

验证四个访问控制权限的使用范围:

❤️例:在com.dlu包下的User类

package com.dlu;

public class User{
	// 私有的
	private int id;
	// 受保护的
	protected int age;
	// 公开的
	public int weight;
	//什么也没有,默认的
	String name;
}

⭐【包没变】在User类(com.dlu)相同包下的Test(com.dlu)类:

只有private修饰的不能访问,区分出来第一个private

package com.dlu;

public class Test{
	public static void main(String[] args){
		User u = new User();
		//System.out.println(u.id); // private私有的不可以访问
		System.out.println(u.age); //protected可以访问
		System.out.println(u.weight); //public可以访问
		System.out.println(u.name); //默认的可以访问
	}
}

⭐【包变了】在User类(com.dlu)不同包下的Test01(com.dlu01)类:

只有public能访问,区分出来第二个public

package com.dlu01; //包变了
import com.dlu.User; //导包

public class Test01{
	public static void main(String[] args){
		User u = new User();
	   //System.out.println(u.id); // private私有的不可以访问
	   //System.out.println(u.age); //protected不可以访问
		System.out.println(u.weight); //public修饰的可以访问
	  //System.out.println(u.name); //默认的不可以访问
	}
}

⭐【包变了】在User类(com.dlu)不同包下的Test02(com.dlu02)类,并且Test02继承User类;protected可以访问,什么都没有的不能访问

package com.dlu02; //包变了
import com.dlu.User; //导包

//User在com.dlu包下;Test在com.dlu02包下;User和Test不在同一个包
//但是Test02是User的子类
public class Test02 extends User{
	public static void main(String[] args){
		Test02 t = new Test02();

		System.out.println(t.age); // protected修饰的可以访问
		//System.out.println(t.name); //默认的不能访问
	}
	
}

🥅Object类

JDK类库的根类:Object

⭐这个老祖宗类中的方法我们需要先研究一下,因为这些方法都是所有子类通用的。
    任何一个类默认继承Objec!就算没有直接继承,最终也会间接继承。

⭐Object类当中有哪些常用的方法?我们去哪里找这些方法呢?
第一种方法:去源代码当中;但是这种方式比较麻烦,源代码也比较难;

        C:\Program Files\Java\jdk-13.0.2\lib\src\java.base\java\lang包下的Object类
第二种方法:去查阅java的类库的帮助文档。

        例如我安装的:jdk1.8:C:\Java学习\javaSE学习\6.JDK帮助文档\jdk8-oracle官方英文-帮助文档\jdk8帮助文档\java\lang下的Object.html
⭐什么是API?
        应用程序编程接口。(Application Program Interface)
        整个JDK的类库(src)就是一个javase的API。
       每一个API都会配置一套API帮助文档。
       SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)

Object 类当中包含的方法有 11 个,这里我们主要关注其中的 6 个:  equals、toString、clone、finalize、getClass、hashCode

protected Object clone()   // 负责对象克隆的(以后接触再讲)。
int hashCode()    // 获取对象哈希值的一个方法。
boolean equals(Object obj)  // 判断两个对象是否相等
String toString()  // 将对象转换成字符串形式
protected void finalize()  // 垃圾回收器负责调用的方法
getClass()  // 返回该 Object运行时类

❤️例1:Object类的toString()方法

(1)源代码

public String toString() {
  return getClass().getName() + "@" + Integer.toHexString(hashCode()); 
} 

toString()方法默认实现是:完整类名+@+对象的内存地址转换为十六进制的形式

(2)Sun公司设计toString()方法的目的是什么? 通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”

(3)建议所有的子类都去重写toString()方法,toString()方法应该是一个简洁的、详实的、易阅读的 

public class ObjectToString {
    public static void main(String[] args) {
        MyTime mt = new MyTime(2022,1,1);
        //重写toString()方法之前
        System.out.println(mt); //MyTime@4554617c;默认会调用toString方法
        //重写toString()方法之后
        System.out.println(mt); //2022年1月1月(简洁的、详实的、易阅读的)
    }
}

class MyTime{ //默认继承Object类
    private int year;
    private int month;
    private int day;
    //构造方法
    public MyTime() {
    }
    public MyTime(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    //重写toString()方法
    public String toString(){
        return this.year+"年"+this.month+"月"+this.day+"月";
    }
}

❤️例2:Object类的equals方法

(1)源代码

public boolean equals(Object obj) {
    return (this == obj);
}

(2)Sun公司设计equals方法的目的是什么? 通过equals方法来判断两个对象是否相等
(3)我们需要研究一下Object类给的这个默认equals方法够不够用?(不够用)

在Object类当中的equals方法当中,默认采用的是“==”判断两个java对象是否相等; 而“==”判断的是两个java对象的内存地址我们应该判断两个java对象的内容是否相等;要使用equals方法!

public class ObjectEquals {
    public static void main(String[] args) {
    //1.判断两个基本数据类型是否相等,直接用“==”
        // "=="是判断a中保存的100和b中保存的100是否相等
        int a = 10;
        int b = 10;
        System.out.println(a == b);// true
    //2.判断两个java对象是否相等呢?(直接用==)
        // 这里的“==”判断的是t1中保存的对象内存地址和t2中保存的对象内存地址是否相等
        MyTime01 t1 = new MyTime01(2008,8,8);
        MyTime01 t2 = new MyTime01(2008,8,8);
        System.out.println(t1 == t2);// false;
        // 但实际上这两个对象表示的时间是一样的,所以这两个对象应该是相同的true,
        // 所以不能用"=="来直接判断两个对象是否相等

    //3.判断两个java对象是否相等呢?(调用equals方法)
        //---重写equals方法之前,默认调用的是Object类的equals方法
        boolean bool = t1.equals(t2);//多态
        System.out.println(bool);
        //---重写equals方法之后
        System.out.println(t1.equals(t2));

    //4.目前程序有bug嘛,如果为空呢?(没有,但是效率低,进行改良)
        MyTime01 t3 = null;
        System.out.println(t1.equals(t3));
        //没有bug,因为下面有instanceof进行判断,空指针直接就return false
    }
}

class MyTime01 { //默认继承Object类
    private int year;
    private int month;
    private int day;

    public MyTime01() {
    }

    public MyTime01(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    //-----------重写equals方法
    public boolean equals(Object obj) {
        //当年、月、日都相同,表示日期相同

        //获取第一个日期的年月日
        int year1 = this.year;
        int month1 = this.month;
        int day1 = this.day;

        //obj访问不到年月日,要想访问子类型中特有的东西,所以要进行向下转型
        if(obj instanceof MyTime01){ //判断
            MyTime01 mt = (MyTime01)obj;
            int year2 = mt.year;
            int month2 = mt.month;
            int day2 = mt.day;

            if(year1 == year2 && month1 == month2 && day1 == day2){
                return true;
            }
        }
        return false;
    }

   /* ------------------代码优化
   public boolean equals(Object obj) {
        //1.先判断空
        if(obj == null){
            return false;
        }
        //2.判断是不是MyTime01对象
        if(!(obj instanceof MyTime01)){
            return false;
        }
        //3.判断内存地址是否相等,内存地址相等,肯定是同一个对象
        if(this == obj){
            return true;
        }
        //4.直接进行比较
        MyTime01 tt = (MyTime01)obj;
        if(this.year == tt.year && this.month == tt.month && this.day == tt.day){
            return true;
        }
        return false;
    }
    */

   /* -------------------代码再次优化  */ 
   public boolean equals(Object obj) {
        if(obj == null || !(obj instanceof MyTime01)){
            return false;
        }
        if(this == obj){
            return true;
        }
        MyTime01 tt = (MyTime01)obj;
        return this.year == tt.year && this.month == tt.month && this.day == tt.day;
    }
       


   /*-----------------也可以利用IDEA自动生成
    public String toString() {
        return "MyTime01{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
    */

}

⭐比较字符串的大小

1、java语言中的字符串String已经重写toString方法和重写equals方法。

2、比较两个两个字符串也不能使用"==";必须调用equals方法。

3、对于字符串比较大小:

如果是直接写出来的,例如:String s = "abc"可以直接用"=="进行比较;

如果是new出来的,例如:String s = new String("abc")就必须使用equals方法进行比较;

所以我们平时就使用equals方法来判断引用数据类型,更加的通用

4、总结:java中基本数据类型比较是否相等,使用"=="

                java中引用数据类型比较是否相等,统一使用equals方法进行判断

public class ObjectEquals02 {
    public static void main(String[] args) {
    //大部分情况下,采用这样的方式创建字符串对象
    String s1 = "hello";
    String s2 = "abc";

    //实际上String也是一个类,不属于基本数据类型,既然是一个类一定有构造方法
    String s3 = new String("Test1");
    String s4 = new String("Test1");
    System.out.println(s3 == s4);//false,因为比较的是内存的地址

    //比较两个两个字符串也不能使用"==";必须调用重写的equals方法
    //对于String类已经重写了String和toString方法
    System.out.println(s3.equals(s4));// true
    //也重写了toString方法
    System.out.println(s3);// Test1
    }
}

⭐一个综合的例题


public class ObjectEquals03 {
    public static void main(String[] args) {
        Student s1 = new Student(1234,"六盘水");
        Student s2 = new Student(1234,"六盘水");
        System.out.println(s1.equals(s2)); // 多态
    }
}

class Student{
    private int id;
    private String school;
    //构造方法
    public Student() {
    }
    public Student(int id, String school) {
        this.id = id;
        this.school = school;
    }

    //当学号和学校相同,表示是同一个学生
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Student)){
            return false;
        }
        if(this == obj){
            return true;
        }
        Student s = (Student)obj; // 向下转型
        return this.id == s.id && this.school.equals(s.school);
    }
}

⭐equals方法深层次理解(重点掌握)

对于equals方法我们重写要彻底!

//equals方法重写要彻底
public class ObjectEquals04 {
    public static void main(String[] args) {
        /*Address1 addr = new Address1("安徽","西城区","1111");
        User1 u = new User1("张三",addr);*/

        //就等价于
        User1 u1 = new User1("张三",new Address1("安徽","西城区","1111"));
        User1 u2 = new User1("张三",new Address1("安徽","西城区","1111"));
        System.out.println(u1.equals(u2));
    }
}

class User1{
    String name;
    Address1 addr;
    //构造方法
    public User1() {
    }
    public User1(String name, Address1 addr) {
        this.name = name;
        this.addr = addr;
    }
    //重写equals
    //规则:当一个用户的用户名和家庭住址都相同,表示同一个用户
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof User1)){
            return false;
        }
        if(this == obj){
            return true;
        }
        User1 u = (User1)obj;
        return this.name.equals(u.name) && this.addr.equals(u.addr);
    }
}

class Address1{
    String city;
    String street;
    String zipcode;
    //构造方法
    public Address1() {
    }
    public Address1(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }

    // 注意:这里如果没有重写equals方法;调用的是Object的equals方法,比较的是addr内存的地址
    // 这里的equals方法判断的是:Address对象和Address对象是否相等
    //所以这里也要重写equals,重写必须彻底!
    //前面String我们没有进行重写是因为默认String类已经重写了equals方法
    public boolean equals(Object obj) {
       if(obj == null || !(obj instanceof Address1)){
           return false;
       }
       if(this == obj){
           return true;
       }
       Address1 address = (Address1)obj;
       return this.city.equals(address.city) && this.street.equals(address.street) && this.zipcode.equals(address.zipcode);
    }
}

❤️例3:Object的finalize方法(了解)

(1)在Object类中的源代码:

   protected void finalize() throws Throwable { }
   // GC:负责调用finalize()方法

(2)finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的

(3)这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法

不像equals、toString方法是需要程序员手动调用的;finalize只需要重写,当垃圾比较多,就会被自动调用;或者调用System.gc()方法(表示建议开启垃圾回收机制),Java虚拟机JVM会自动会自动调用垃圾回收机制,但是也有可能不开启(只是建议开启)!

(4)finalize执行的时机:

   当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法

(5)finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机

   如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法中

(7)回顾:静态代码块的作用是什么?static{....}

   静态代码块在类加载时刻执行,并且只执行一次,这是一个SUN准备的类加载时机

   finalize()方法同样也是SUN为程序员准备的一个时机,这个时机是垃圾回收时机

(8)java中的垃圾回收器不是轻易启动的,垃圾太少,或者时间没到等,也有可能不启动 

(9)System.gc():建议启动垃圾回收机制;实际上JVM会自动调用gc()方法中的finalize方法

注:finalize在JDK9之后就过时了,因为可能会导致内部出现循环引用,导致此对象不能被回收!

public class ObjectFinalize {
    public static void main(String[] args) {
        /*Person1 p = new Person1();
        // 怎么把Person对象变成垃圾?
        p = null; // 这里可能就没有启动

        //多造点垃圾,就可以启动
        for(int i=0;i<1000000;i++){
            Person1 p1 = new Person1();
            p1 = null;
        }*/

        //有一段代码可以建议垃圾回收器启动
        Person1 p = new Person1();
        p = null;
        System.gc();// 建议启动垃圾回收器(增加启动的可能性增大了)

    }
}

class Person1{
    // 重写finalize方法
    // Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用p.finalize();
    protected void finalize() throws Throwable {
        System.out.println(this+"即将被销毁!");
    }
}

❤️例4:Object的hashCode方法

1、在Object中的hashCode方法是怎样的?     

 public native int hashCode();
 // 这个方法不是抽象方法,带有native关键字,底层调用C++程序。

2、hashCode()方法返回的是哈希码:

      实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值

      所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址

public class ObjectHashCode{
    public static void main(String[] args){
        Object o = new Object();
        int hashCodeValue = o.hashCode();
        // 对象内存地址经过哈希算法转换的一个数字。可以等同看做内存地址。
        System.out.println(hashCodeValue); //1163157884

        MyClass mc = new MyClass();
        int hashCodeValue2 = mc.hashCode();
        System.out.println(hashCodeValue2); //1956725890

    }
}

class MyClass
{
}

❤️例5:Object的clone方法

clone()方法的约定

Cloneable接口的目的是作为对象的一个混合接口,表明这样的对象允许克隆(clone),但是这个接口却没有定义clone()方法,这是它的缺陷:无法约束子类实现clone()方法。Object定义了一个受保护的clone()方法。Cloneable虽然没有定义clone()方法,但是却影响了Object.clone()方法的行为:如果一个类实现了Cloneable,调用Object的clone()就会返回该对象的逐域拷贝,否则抛出CloneNotSupportedException。这真是一种非常规的用法,Cloneable接口没有规定实现类的视图,却改变了父类受保护方法的行为。调用clone()会创建并返回对象的拷贝,看看JDK文档中对clone()方法的约定:

(1)x.clone() != x; 克隆对象与原对象不是同一个对象

(2)x.clone().getClass() == x.getClass(); 克隆的是同一类型的对象

(3)x.clone().equals(x) == true,如果x.equals()方法定义恰当的话

package com.zl.test;

public class Test {
    public static void main(String[] args) {
       // 创建对象
        User u1 = new User("张三", 18);
        System.out.println("当前对象的地址:"+u1);
        // 拷贝clone
        User u2 = u1.clone();
        System.out.println("克隆后的对象:"+u2);
    }
}

// 实现Cloneable接口,重写clone方法
class User implements Cloneable{
    private String name;
    private int age;




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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    // 重写clone方法
    @Override
    public User clone() {
        try {
            User clone = (User) super.clone();
            // TODO: copy mutable state here, so the clone can't change the internals of the original
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }



}

执行结果:指向的不是同一块内存空间,实际上是又new的,但是存储的内容确实相同的;所以clone可以作为一种创建对象的方式。

❤️例6:Object的getClass方法

public final Class getClass():获取对象的运行时类型 因为 Java 有多态现象,所以一个引用数据类型的变量的编译时类型与 运行时类型可能不一致,因此如果需要查看这个变量实际指向的对象 的类型,需要用 getClass()方法 。

package com.zl.test;

import java.util.Date;


public class Test {
    public static void main(String[] args) {
        // 打印时间
        Date date = new Date();
        System.out.println(date.getClass()); // class java.util.Date
    }
}

🥅匿名内部类

❤️内部类概述

匿名内部类:

1、什么是内部类?

内部类:在类的内部又定义了一个新的类;被称为内部类

2、内部类的分类:

静态内部类:类似于静态变量

实例内部类:类似于实例变量

局部内部类:类似于局部变量(匿名内部类属于局部内部类

3、使用内部类编写的代码,可读性很差,能不用尽量不用。

4、匿名内部类是局部内部类的一种

因为这个类没有名字而得名,叫做匿名内部类。

5、学习匿名内部类主要是以后在阅读别人代码的时候,能够理解;并不代表以后都要这样写;因为匿名内部类有两个缺点:

缺点1:太复杂,太乱,可读性差。

缺点2:类没有名字,以后想重复使用,不能用。

public class InnerTest01{

    // 静态变量
    static String country;
    //1. 静态内部类
    static class Inner1{
    }
    // 实例变量
    int age;
    //2. 实例内部类。
    class Inner2{
    }
    // 方法
    public void doSome(){
        // 局部变量
        int i = 100;
        //3. 局部内部类。
        class Inner3{
        }
    }
    
    public void doOther(){
        // doSome()方法中的局部内部类Inner3,在doOther()中不能用。
    }
    
//--------------------------------------------------------------------    
    
    // main方法,入口
    public static void main(String[] args){
        // 调用MyMath中的mySum方法。
        MyMath001 mm = new MyMath001();
		/*
		Compute c = new ComputeImpl();
		mm.mySum(c, 100, 200);
		*/

        //代码合并
        //我们调用的时候里面传的是接口Compute c:mySum(Compute c, int x, int y);
        //所以这里调用应该需要new一个接口传进去,又因为接口是抽象类,不能new对象,
        //所以要写一个类ComputeImpl去实现接口,用来new对象
        mm.mySum(new ComputeImpl(), 100, 200); 

    }

}

// 负责计算的接口
interface Compute{
    // 抽象方法
    int sum(int a, int b);
}

// 编写一个Compute接口的实现类ComputeImpl
class ComputeImpl implements Compute{
	// 对方法的实现
	public int sum(int a, int b){
		return a + b;
	}
}

// 数学类
class MyMath001{
    // 数学求和方法
    public void mySum(Compute c, int x, int y){ //Compute c 把这个接口看成String name更好理解
        int retValue = c.sum(x, y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}

❤️内部类的使用

使用匿名内部类,下面ComputeImpl类实现Compute接口就不需要写了!对于匿名内部类能看懂代码就行,可读性差,且不能重复使用!

总结:使用匿名内部类对于接口的实现类就不用写了,实际上我们就可以简单理解为:就是new接口,然后大括号,在这个大括号里重写接口中的方法!

public class InnerTest02{

    // main方法,入口
    public static void main(String[] args){
        // 调用MyMath中的mySum方法。
        MyMath001 mm = new MyMath001();
        //我们不使用Compute接口的实现类ComputeImpl;使用匿名内部类实现
        //mm.mySum(new ComputeImpl(), 100, 200);

        //使用匿名内部类,记住语法;以后能看懂就行
        mm.mySum(new Compute() {
            public int sum(int a, int b) {
                return a+b;
            }
        },100,200);

    }

}

// 负责计算的接口
interface Compute{
    // 抽象方法
    int sum(int a, int b);
}

//-------使用匿名内部类,接口的实现就不需要了
/*// 编写一个Compute接口的实现类ComputeImpl
class ComputeImpl implements Compute{
    // 对方法的实现
    public int sum(int a, int b){
        return a + b;
    }
}*/

// 数学类
class MyMath001{
    // 数学求和方法
    public void mySum(Compute c, int x, int y){ //Compute c 把这个接口看成String name更好理解
        int retValue = c.sum(x, y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}

  • 115
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 107
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@每天都要敲代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值