目录
内部类引出
内部类作为oop的最后一个部分,它的重要性不言而喻,在许多底层源码中内部类被大量使用。由它的名字就很容易知道,所谓内部类,就是定义在类的内部的一种类,如以下代码所示:
class Outer{ //外部其他类
}
class Outer01{ //外部类
class Inner{ //内部类
}
}
内部类的分类
内部类可以根据它定义的位置分成两大类
定义在类的局部位置:局部内部类,匿名内部类
定义在类的成员位置:成员内部类,静态内部类
局部内部类
public class Java实验 { //外部其他类
public static void main(String[] args) {
Person person = new Person(); //实例化外部类的对象
person.get(); //进行输出
}
}
class Person{ //外部类
private String name = "小黄";
public char sex = '男';
public int age = 19;
public void get(){
class GetPerson{ //局部内部类
public void call(){
System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + age);
}
}
new GetPerson().call(); //在方法内创建内部类的实例并调用内部类的方法
}
}
输出结果
姓名:小黄 性别:男 年龄:19
由以上代码可知,局部内部类具有以下特点:
1:定义在类的局部位置(方法或代码块)中,具有类名;
2:可以访问外部类的所有属性,包括私有属性;
3:作用域为定义它的方法或代码块;
4:外部其他类不能访问局部内部类。如果要使用,可以在定义它的方法中创建它的实例,然后调用内部类成员。并在外部其他类中创建外部类的实例调用该方法。
局部内部类使用注意:
1:局部内部类的本质依然是类,因此可以有类的所有成员;
2:局部内部类可以被继承(只能在定义它的作用域中被继承);
3:局部内部类不能加访问修饰符,要加也只能加final,加了final的内部类不能被继承;
4:如果外部类的成员和内部类重名时,遵循就近原则。
代码示例:
public class Java实验 {
public static void main(String[] args) {
Person person = new Person();
person.get();
}
}
class Person{
private String name = "小黄";
public char sex = '男';
public int age = 19;
public void get(){
class GetPerson{
public void call(){
System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + age);
}
}
//局部内部类可以被继承
class GetSthdent extends GetPerson{
//局部内部类可以有类的所有成员(本质还是类)
private String name = "小红";
public char sex = '女';
public int age = 20;
public char grade = 'A';
//当内部类的成员和外部类的成员重名时,默认遵循就近原则
//如果还是希望访问外部类的成员,可以用语法:外部类名.this.成员 来访问
public void call(){
System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + Person.this.age + " 等级:" + grade);
}
}
new GetSthdent().call();
}
}
输出结果:
姓名:小红 性别:女 年龄:19 等级:A
注:就近原则:执行操作有重名的成员的语句时,被操作的成员默认是离该语句最近的成员。
对语法 外部类名.this.成员 的解释:外部类名.this---相当于指定外部类的对象,如果直接写this.成员,指定的是当前局部内部类的成员,但外部类名.this指定的是所写外部类的成员;
匿名内部类引出
public class Java实验 {
public static void main(String[] args) {
Person person = new Person(); //创建人的对象
person.run(); //使用跑步功能
}
}
interface A{ //接口
String name = "小黄";
void run();
}
class Person implements A{ //Person类实现接口A,实现人的跑步功能
public void run(){
System.out.println(name + "跑的很快!");
}
}
以上代码展示了传统写法中我们实现并使用接口规定的方法时,需要专门写一个类实现接口的方法。但是我们在实际开发中又只使用一次该方法,这么写很不方便;
因此我们可以用匿名内部类来简化代码
基于接口的匿名内部类
public class Java实验 {
public static void main(String[] args) {
Person person = new Person(); //创建对象调用get方法
person.get();
}
}
interface A{
String name = "小黄";
void run();
}
class Person{
public void get(){
A person = new A(){ //使用匿名内部类实现接口
public void run(){ //实现接口的方法
System.out.println(name + "跑的很快");
}
};
person.run(); //调用匿名内部类的方法
}
}
运行结果:
小黄跑得很快
由以上代码可知
1:编译类型是接口A,运行类型是匿名内部类;
2:此匿名内部类实现了接口A,可以重写run方法;
3:可以访问外部类的所有成员。
基于类的匿名内部类
public class Java实验 {
public static void main(String args[]){
Person person = new Person();
person.call(); //进行输出
}
}
class Person{
private String name = "小黄";
private int age = 19;
public char sex = '男';
public void get(){
System.out.println("姓名:" + name + " 年龄:" + age + " 性别:" + sex);
}
public void call(){
Person student = new Person(){ //使用匿名内部类
private char grade = 'A';
public void get(){ //进行输出(方法重写)
System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + age + " 等级:" + grade);
}
};
student.get(); //调用匿名内部类的方法
}
}
运行结果:
姓名:小黄 年龄:19 性别:男 等级:A
匿名内部类除了可以基于接口使用,还可以基于类使用:
由以上代码可知:
1:编译类型是Person类,运行类型是匿名内部类;
2:此匿名内部类继承了Person类,可以使用Person类的成员;
3:可以访问外部类的所有成员。
匿名内部类总结
1:语法:类名(接口名) 引用 = new 类名(接口名);
注:如果使用的是接口名创建匿名内部类,则会默认用匿名内部类实现该接口,可以实现接口中的方法。
如果使用的是类名创建匿名内部类,则会默认用匿名内部类继承该类,可以使用此类中的成员。
匿名内部类的地址会返回给引用,可以用引用调用匿名内部类的方法;
2:匿名内部类的末尾需要打分号;
3:匿名内部类的作用域是定义它的方法或代码块;
4:匿名内部类不是没有名字,而是名字由系统分配,定义者不可见;
注:匿名内部类的名字:外部类名+$n(n为根据定义的匿名内部类的个数分配的编号);
此代码在JVM底层相当于如下语句:
class Person$1 extends Person{
private char grade = 'A';
public void call(){
System.out.println("姓名:" + name + " 年龄:" + age + " 性别:" + sex + " 等级:" + grade);
}
}
成员内部类
public class Java实验 {
public static void main(String args[]) {
Person person = new Person();
person.user(); //调用user方法
}
}
class Person{
private String name = "小黄";
private int age = 19;
public char sex = '男';
public class Student{ //成员内部类
char grade = 'A';
public void call(){ //成员内部类的方法
System.out.println("姓名:" + name + " 年龄:" + age + " 性别:" + sex + " 等级:" + grade);
}
}
public void user(){ //所有方法创建成员内部类的实例,并调用成员内部类的方法
Student student = new Student();
student.call();
}
}
输出结果
姓名:小黄 年龄:19 性别:男 等级:A
由以上代码所示,成员内部类由以下特点:
1:成员内部类定义在外部类的成员位置,没有static修饰;
2:可以直接访问外部类的所有成员,包含私有的;
3:可以添加任意的的访问修饰符;
4:作用域和外部类的其他成员一样,为整个类体;
外部其他类的访问方式 :
1:在外部其他类中直接创建成员内部类的对象,语法:外部类名.成员内部类名 引用 = new 外部类名.new 成员内部类名;
2:在外部类中用一个方法创建成员内部类的对象调用成员内部类,在外部其他类中创建外部类的对象调用此方法。(如以上代码) 。
第一种方式示例:
public class Java实验 {
public static void main(String args[]) {
Person.Student student = new Person().new Student(); //直接创建内部类的对象
student.call();
}
}
class Person{
private String name = "小黄";
private int age = 19;
public char sex = '男';
public class Student{ //成员内部类
char grade = 'A';
public void call(){ //成员内部类的方法
System.out.println("姓名:" + name + " 年龄:" + age + " 性别:" + sex + " 等级:" + grade);
}
}
}
输出结果同上。
静态内部类
public class Java实验 {
public static void main(String args[]) {
Person person = new Person();
person.f1();
}
}
class Person{
static private String name = "小黄";
static private int age = 19;
public char sex = '男';
static class Student{ //静态内部类
char grade = 'A';
static void call(){ //静态内部类的方法
System.out.println("姓名:" + name + " 年龄:" + age);
}
}
public void f1(){
Student.call(); //使用类名直接调用
}
}
运行结果:
姓名:小黄 年龄:19
由以上代码所示,静态内部类具有以下特点:
1:静态内部类有static修饰,定义在类的成员位置;
2:可以直接访问外部类的所有静态成员,包含私有的,但不能访问非静态成员;
3:可以添加任何访问修饰符;
4:作用域和其他成员一样,为整个类体;
访问方式:
1:直接在外部其他类创建对象:语法:外部类名.静态内部类名 引用 = new 外部类名.静态内部类名;
2:在外部类中使用方法创建静态内部类的对象调用静态内部类,在外部其他类中创建外部类的对象调用此方法;(如以上代码)
第一种方式示例:
public class Java实验 {
public static void main(String args[]) {
Person.Student student = new Person.Student(); //直接创建静态内部类的对象
student.call();
}
}
class Person{
static private String name = "小黄";
static private int age = 19;
public char sex = '男';
static class Student{ //静态内部类
char grade = 'A';
static void call(){ //静态内部类的方法
System.out.println("姓名:" + name + " 年龄:" + age);
}
}
}
输出结果同上。