欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【内部类、匿名内部类、API】的学习

程序员文章站 2022-09-02 16:55:13
内部类概念在一个类中书写另一个类分类同级类(严格意义上来讲只是一种书写形式不是内部类)成员内部类(全局内部类)局部内部类(包含匿名内部类)①同级类在当前类同级下继续书写其他类,书写语法与普通类相同,但修饰符只能使用默认在使用时与普通类一致,只是访问范围只有本包下,将相当于少创建了一个文件//员工类public abstract class Employee {public String name;// 姓名public int birthdayMonth;// 生日月份pu...

内部类

概念

在一个类中书写另一个类

分类

同级类(严格意义上来讲只是一种书写形式不是内部类)

成员内部类(全局内部类)

局部内部类(包含匿名内部类)

①同级类

在当前类同级下继续书写其他类,书写语法与普通类相同,但修饰符只能使用默认

在使用时与普通类一致,只是访问范围只有本包下,将相当于少创建了一个文件

//员工类
public abstract class Employee {
	public String name;// 姓名
	public int birthdayMonth;// 生日月份
	public double salary;// 薪资

	public abstract void getSalary(int month);

}

// 同级类的形式
class sale extends Employee {
	public double saleMoney;// 销售额
	public double rate;// 提成率

	@Override
	public void getSalary(int month) {	
		salary+=saleMoney*rate;
		if(birthdayMonth==month){
			salary+=100;
		}
		System.out.println("销售员"+name+month+"月份的工资为:"+salary);
	}
}

②成员内部类(全局内部类)

书写在类体中的类

修饰符 class 类名称 {
    修饰符 class 类名称 {
        //...
    }
    //...
}
public class A {
	int aa;
	// 成员内部类
	// 在一个类中书写另一个类
	public class B {
		// 内部类可以随意访问外部类(包含其他外部类)
		public void b() {
			// 直接访问当前外部类
			A a = new A();
			// 可以直接访问其他外部类
			A1 a1 = new A1();
			int b=A.this.a;//内部类可以直接使用外部类的属性
			//由于就近原则当出现属性与外部类相同时,使用语法
			//外部类.this.属性名进行指定
		}
	}

	public void a() {
		B b = new B();
		b.b();
	}
}

class A1 {
	// 内部类的调用
	public static void main(String[] args) {
		// 1、间接调用
		// 其他外部类不能直接访问但是书写内部类的外部类可以访问
		// 在外部类声明方法创建内部类对象调用方法
		// 在其他类中创建外部类调用内部类方法
		A a = new A();
		a.a();// 实际调用内部类b方法
		// 2、直接调用
		//直接在其他外部类创建内部类对象
		//语法:外部类.内部类 标识符 =new 外部类().new 内部类();
		A.B b=new A().new B();
		//可以将内部类当做变量,如果想获取一个类的成员变量那么必须先创建这个类的对象
		//之后因为是一个类 如果想使用必须创建对象
		b.b();//直接使用B对象调用b方法
	}

}

成员内部类总结:

1、书写在类体中的类

2、只能由当前类的外部类直接访问

3、可以直接访问外部类(其他外部类)

4、使用同名外部类变量时注意语法 外部类.this.属性名

5、其他外部类访问方式 间接方式(创建外部类通过外部类方法使用内部类) 直接方式(通过外部类直接创建内部类对象)

③局部内部类

如果类是定义在一个方法内部的,那么这就是一个局部内部类。

“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

修饰符 class 外部类名称 {
    修饰符 返回值类型  外部类方法名称(参数列表) {
        class 局部内部类名称 {
            //...
        }
    }
}
public class B {
	int b = 1;

	// 局部内部类
	// 在方法体中定义的类
	public void b() {
		int b = 2;
		// 由于方法中变量在方法执行结束后会释放
		// 并且只能由当前方法调用,所以修饰符不能使用public
		class C {
			int c = 3;

			public void c() {
				System.out.println(c);
				System.out.println(b);// 可以直接使用方法中的变量
				System.out.println(B.this.b);// 通过固定语法访问同名全局变量
				// 当局部内部类使用方法中的变量时,一般使用final修饰
				// 由于其数据存储空间不同,在执行时可能导致错误
				// 1. new 出来的对象在堆内存当中。
				// 2. 局部变量是跟着方法走的,在栈内存当中。
				// 3. 方法运行结束后,立刻出栈,局部变量就会立刻消失。
				// 4. 但是new出来的对象在堆当中持续存在,直到垃圾回收消失。

			}
		}
		C c = new C();
		c.c();
	}

	public void b1() {
		// 其他方法不能调用局部内部类,只能通过间接调用
	}

	public static void main(String[] args) {
		B b = new B();
		b.b();
	}
}

局部内部类总结:

1、书写在方法体中的类

2、只能由当前方法直接访问

3、可以直接访问外部类(其他外部类)

4、使用同名方法所在类变量时注意语法 外部类.this.属性名(对于方法中同名属性不能直接调用建议改名)

5、其他外部类(方法)访问方式 间接方式(通过访问方法的形式进行调用)

6、局部内部类使用方法中变量的值实际过程是创建空间将值复制过来进行使用,要求变量理论不变的原因,是因为回收时机不同,可能导致程序错误(局部内部类不建议使用方法中的属性进行属性的赋值)

修饰内部类的权限

public > protected > (default) > private

定义一个类的时候,权限修饰符规则:

外部类:public / (default)

成员内部类:都可以写,public > protected > (default) > private

局部内部类:什么都不能写,但不是default

匿名内部类

属于局部内部类,书写在方法中但创建类无需类名与class关键字,只需要书写方法体{}

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次。

那么这种情况下就可以省略调该类的定义,而改为使用【匿名内部类】。

匿名内部类用于创建子类或者实现类

接口(父类) 对象名 = new 类名或者接口名称() {
    //覆盖重写所有抽象方法
};
public interface C {
	void a();
	void b();
	void c();
}

class Test{
	public static void main(String[] args) {
		//匿名内部类就是省略类的声明与命名只书写类体{}
		//一般用于只使用一次的子类或实现类
		C c=new C(){
			@Override
			public void a() {
				System.out.println("a");
			}
			@Override
			public void b() {
				System.out.println("b");
			}
			@Override
			public void c() {
				System.out.println("c");
			}
		};
		//会直接使用匿名内部类创建一个唯一对象
		//这个对象只有一个,因为没有类
		//相当于使用类体临时创建了一个类并用其创建对象	
		c.a();
	}
}

匿名对象:

创建的对象只调用一次方法那么可以直接使用new 类名().方法()进行使用

注意:

匿名对象与匿名内部类不是同一个东西

匿名对象省略了类的声明

匿名内部类省略了class关键字以及类名

匿名内部类总结

1、匿名内部类由于没有创建类,所以使用父类或者接口声明变量保存遵循多态,只能使用重写的方法以及父类的属性,但是重写的方法可以使用这些属性,只不过不能通过对象进行赋值,(一般在使用匿名内部类的时候不会创建属性只重写方法)

API

概念

API全名:application(应用) programming(程序) interface(接口)
API是应用程序编程接口

Java API

Java API就是sun公司提供给我们使用的类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。
我们可以通过查帮助文档来了解Java提供的API如何使用

Object类

Object类是所有类的父类,所有类都字节或间接的继承与Object类

Object类中提供了所有类都一定拥有的方法由java决定

常用方法

【内部类、匿名内部类、API】的学习
getClass:之后反射部分会讲

notify、notifyAll、wait:之后多线程会讲

toString方法

将对象转换为字符串,Object类转换字符串的方法类似于打印地址

​ Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
​ 所有的类都继承于Object类所有都继承了这个方法,当进行对象的输出时默认调用该对象的toString()方法,将返回的字符串在控制台进行打印

在调用输出语句输出对象时,实际上时自动调用对象toString方法将对象转换为字符串之后进行输出

一般我们会重写这个方法,这样在进行对象输出时就会按照我们定义的方式进行输出

hashCode方法

每个对象是唯一的,即使多个对象属性方法全部相同那么也是多个对象,在java中为了对对象进行同一对象验证提供了hashCode方法,用于返回对象的唯一hashCode值

​ 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

​ hashCode值在对象运行过程中唯一不重复

两个对象hashCode值相等不一定是同一对象,但同一对象多次调用hashCode方法返回hashCode值一定相等

		String s1="柴柕";
		String s2="柳柴";
		System.out.println(s1.hashCode());//851553
		System.out.println(s2.hashCode());//851553

equals方法

​ Object类提供的equals()方法比较的是对象的内存地址.当两对象指向内存地址相同时,返回true
​ Object提供的方法不适用其他子类,所以,基本上所有子类都对equals方法进行了重写

子类如果重写equals方法那么必须重写hashCode方法

两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

equals与==的区别

1、语法上的区别

==是算术运算符 equals是方法

2、判断内容不同

==经常用于判决基本数据类型数值类型是否相等,也可以判断两个对象地址是否相等(同一对象)

equals只能判断引用数据类型

3、对于object类而言equals与==没有区别

equals默认使用==判断两对象是否相同

4、对于其他类重写equals方法而言的不同(String为例)

==判断的是两对象地址是否相同。equals判断的是两字符串对象内容是否相同

String类

引用数据类型,用于保存字符串,Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。

字符串为常量,字符串值一旦初始化便不可以修改。
常量池:在java用于保存在编译期已确定的,已编译的class文件中的一份数据。

		String s = "abc";
		s="bcd";
		//变量s保存的是常量abc所在的地址
		//当重新赋值时会将新的常量地址进行赋值
		//但是原字符串abc会一直存储在常量池中直至程序运行结束
		String s1="bcd";
		System.out.println(s==s1);
		//因为相同常量只创建一次。再次使用直接将地址进行赋值

String 可以理解为特殊的字符数组

构造方法

String()
初始化一个新创建的 String 对象,使其表示一个空字符序列。

String(byte[] bytes)
通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

String(byte[] bytes, int offset, int length)
通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。

String(char[] value, int offset, int count)
分配一个新的 String,它包含取自字符数组参数一个子数组的字符。

String(String original)
初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。

		String  s1=new String();//等价String s1="";
		String  s11=new String();
		//由于使用new关键字创建的新对象虽然存储字符串相同但地址不同
		//原因:对象存储数据为位置与常量存储位置不同
		//System.out.println(s1==s11);
		
		byte b[]={65,66,67,68};
		String s2=new String(b);
		//将数值对应字符编码进行转换之后连接
		System.out.println(s2);//ABCD
		
		String s3=new String(b,1,2);
		//使用数组部分数据从索引1开始之后的2位数据
		System.out.println(s3);//BC
		
		char c[]={'a','b','c','d'};
		String s4=new String(c);
		System.out.println(s4);
		String s5=new String(c,0,2);
		System.out.println(s5);
		String str1="hello";
		String str2=" world!";
		String str3="hello world!";
		String str4=str1+str2;
		String str5="hello"+" world!";
		System.out.println(str3==str5);
		System.out.println(str4==str5);

常用方法

charAt(int index)
返回指定索引处的 char 值。

indexOf(String ch)
返回指定字符在此字符串中第一次出现处的索引。

isEmpty()
当且仅当 length() 为 0 时返回 true。

lastIndexOf(String ch)
返回指定字符在此字符串中最后一次出现处的索引。

length()
返回此字符串的长度。

replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。

split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串。

startsWith(String prefix)
测试此字符串是否以指定的前缀开始。

toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。

contains(CharSequence s)
当且仅当此字符串包含指定的 char 值序列时,返回 true。

		String str="abcdefgc";
		// charAt(int index)
		// 返回指定索引处的 char 值。
		//String底层使用char数组进行数据存储所以可以直接返回某一索引数据
		char charAt = str.charAt(0);
		System.out.println(charAt);//a

		// indexOf(String ch)
		// 返回指定字符在此字符串中第一次出现处的索引。
		int indexOf = str.indexOf("c");
		System.out.println(indexOf);//2
		
		
		// lastIndexOf(String ch)
		// 返回指定字符在此字符串中最后一次出现处的索引。
		int lastIndexOf = str.lastIndexOf("c");
		System.out.println(lastIndexOf);//7
		

		// isEmpty()
		// 当且仅当 length() 为 0 时返回 true。
		//判断字符串是否为空字符串""
		boolean empty = str.isEmpty();
		System.out.println(empty);
		
	
		// length()
		// 返回此字符串的长度。
		//返回存储数组的长度
		int length = str.length();
		System.out.println(length);//8

		// replace(char oldChar, char newChar)
		// 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
		String replace = str.replace("c", "CC");
		System.out.println(replace);//abCCdefgCC

		// split(String regex)
		String[] split = str.split("c");
		//以指定字符进行字符串截取返回字符串数组
		for (int i = 0; i < split.length; i++) {
			System.out.print(split[i]+" ");
		}
		System.out.println();
		// startsWith(String prefix)
		// 测试此字符串是否以指定的前缀开始。
		boolean startsWith = str.startsWith("abc");
		System.out.println(startsWith);
		
		// String toUpperCase()
		// 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
		String upperCase = str.toUpperCase();
		System.out.println(upperCase);
		
		// toLowerCase()
		// 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
		String lowerCase = upperCase.toLowerCase();
		System.out.println(lowerCase);
		
		// contains(CharSequence s)
		// 当且仅当此字符串包含指定的 char 值序列时,返回 true。
		boolean contains = str.contains("cdef");
		System.out.println(contains);
		
		
		//String很多方法会返回新的字符串
		//因为String存储的是常量 不允许修改,所以只能产生新的字符串保存结果
		//不会修改原字符串数据
		//但是会加大程序的负担
		System.out.println(str);

总结:

1、String存储字符串常量不允许更改

2、String返回新的字符串不会修改本身

3、使用构造方法创建字符串对象与直接赋值存在差别

4、String本质是字符数组

本文地址:https://blog.csdn.net/Y_W_LIANG/article/details/109604651

相关标签: java