文章内容比较基础,并不设计到源码部分,只告诉读者怎么和如何去用,适合于刚学习的小伙伴,内容难免有部分遗留和不足,还请各位及时批评指正。
java类有五大特效,属性,方法,构造器,代码块,内部类。
本文主要介绍的便是其中的内部类。
内部类的使用目的:减少代码的冗余量简化开发
内部类根据其所在的位置和相应语法有着不同的分类,其中主要可划分为以下四类:
定义在外部类(平时定义的类)的局部位置上的(方法中或者外部类属性的位置):
1.局部内部类(有类名)
类似于C语言中的局部变量,只不过此处我们把整个类当成局部的,本质上还是一个类,在外部类中我们可以访问内部类创建的对象以及使用相关的方法,也可以在内部类中用外部类类名.this.属性方法来使用外部类属性。
public class InnerClass {
public static void main(String[] args) {
new A().w1();
}
}
//A类为外部类
class A {
//A类的属性
private int A_num = 100;
public void w1() {
//A的内部类A_In
class A_In {
//内部类属性
private int A_In_num = 200;
//以下皆为内部类方法
public int getA_In_num() {
return A_In_num;
}
public void setA_In_num(int a_In_num) {
A_In_num = a_In_num;
}
public void w2() {
System.out.println("在内部类A_In中调用外部类A的num值: " + A.this.A_num);
}
}
//创建内部类对象
A_In my_In = new A_In();
System.out.println("内部类A_In的属性A_In_num = " + my_In.getA_In_num());
my_In.w2();
}
}
此处我们是在方法中创建了内部类,在方法外的位置创建也可以调用之后我们可以看到输出结果
值得一提的是,虽然内部类用法看上去和类一样,有着近乎一样的用法,但二者在细节上仍有差异。
1.内部类不能添加访问修饰符,除了final(在方法中)。
2.内部类可以继承,保留了外部类的特性。
可以看到idea自动对方法中的内部类public修饰符进行报错,并且内部类之间是可以继承的,方法外的内部类(即成员内部类,后面会涉及到)正常
2.匿名内部类( 无类名)
顾名思义,匿名表示类没有名字,即没有相对应的类名(由系统进行取名)
同时匿名内部类是一个对象。
当我们想利用接口时,传统方法是创建一个类继承接口实现方法,匿名内部类可以简化这种操作,直接实现接口的方法,示例如下
public class AnonymousClass {
public static void main(String args[]) {
Animal animal = new Animal();
animal.m1();
}
}
class Animal {
public void m1() {
Act cat = new Act() {
@Override
public void cry() {
System.out.println("小猫在哭。");
}
};
cat.cry();
System.out.println("匿名内部类的运行类型为" + cat.getClass());
}
}
interface Act {
public void cry();
}
运行结果如下
可以看到运行类型为Animal$1,我们并没有设计这个类,为系统自己创建的类。
当后续再创建时,会变成Animal$2。
类与接口的方式类似,均可由这种方式创建匿名内部类,如下
public class AnonymousClass02 {
public static void main(String[] args) {
Animal animal = new Animal();
animal.sayHi();
}
}
class Animal{
public void sayHi(){
//创建匿名内部类
Monkey monkey = new Monkey(){
@Override
public void hi() {
System.out.println("匿名内部类的hi()方法..");
}
};
monkey.hi();
}
}
class Monkey{
//提供方法
public void hi(){};
}
运行结果如下
细节:
1.内部类可以在访问外部类的变量,包括私有变量。
2.匿名内部类不能添加访问修饰符。
3.如果想访问外部类,可以采用外部类.this.类名的方法访问,如上述类似
public class AnonymousClass02 {
public static void main(String[] args) {
Animal animal = new Animal();
animal.sayHi();
animal.sayHi2();
}
}
class Animal{
private int num = 100;
public void sayHi(){
//创建匿名内部类
Monkey monkey = new Monkey(){
@Override
public void hi() {
System.out.println("第一个匿名内部类的hi()方法..");
System.out.println("Animal类的num = " + num);
}
};
monkey.hi();
System.out.println(monkey.getClass());
}
public void sayHi2(){
Monkey monkey2 = new Monkey(){
@Override
public void hi() {
System.out.println("第二个匿名内部类hi()方法");
}
};
monkey2.hi();
System.out.println(monkey2.getClass());
}
}
class Monkey{
//提供方法
public void hi(){};
}
运行结果如下
匿名内部类可以明显减少代码量,以下给出实例
public class test {
public static void main(String[] args) {
M1(new IA() {
@Override
public void hi() {
System.out.println("why so serious?");
}
});
}
public static void M1(IA ia){
ia.hi();
}
}
interface IA{
public void hi();
}
传统代码需要创建类实现接口,并创建对象调用方法,无疑会增加很多代码量,采用内部类可以大大加快开发速率,减少代码量。
以下为运行结果
3.成员内部类(定义在外部类局部位置)
成员内部类的位置也在外部类中,只不过与局部内部类(通常定义在方法内)不同,是定义在局部位置上的。成员内部类可以调用外部类的方法和属性。下面给出例子
public class memberInnerClass {
public static void main(String[] args) {
Member_1 member_1 = new Member_1();
member_1.show();
}
}
class Member_1{
//外部类私有变量
private int num_1 = 100;
//成员内部类
class Member_2{
private int num_2 = 200;
//成员内部类方法
public void show_num(){
System.out.println("成员内部类的show_num方法");
System.out.println("获取到的num值为:" + num_1);
}
}
//外部类方法
public void show(){
Member_2 member_2 = new Member_2();
member_2.show_num();
}
}
可以用修饰符修饰成员内部类,本文采用的默认修饰符修饰。通过调用外部类的show方法使用成员内部类的show_num方法。以下为运行结果。
成员内部类的关键在于内部类的创建。我们有两种方式实现。
1.在主方法中先生成外部类,再生成成员内部类,即连续new 两个类。
2.通过外部类方法返回成员内部类。
细节:访问相同变量名的时候采用的就近原则,如果想访问外部类的变量名采用和局部内部类一样的方法即可。
public class memberInnerClass {
public static void main(String[] args) {
//连续new两个类创建成员内部类
Member_1.Member_2 member_2_1 = new Member_1().new Member_2();
System.out.println("获得的member_2_1的类为" + member_2_1.getClass());
//调用外部类的方法创建成员内部类
Member_1.Member_2 member_2_2 = new Member_1().getInstanceMember_2();
System.out.println("获得的member_2_2的类为" + member_2_2.getClass());
//成员内部类方法
member_2_2.show_num();
}
}
class Member_1{
//外部类私有变量
private int num_1 = 100;
//成员内部类
class Member_2{
private int num_2 = 200;
private int num_1 = 300;
//成员内部类方法
public void show_num(){
System.out.println("成员内部类的show_num方法");
//当方法重名时,就近原则获取值
System.out.println("获取到的num_1值为:" + num_1);
System.out.println("获取到的外部类num_1" + Member_1.this.num_1);
}
}
//外部类方法
public void show(){
Member_2 member_2 = new Member_2();
member_2.show_num();
}
//外部类方法返回成员内部类
public Member_2 getInstanceMember_2(){
return new Member_2();
}
}
下面是运行结果
4.静态内部类(定义在外部类局部位置,用static修饰)
使用了static修饰,使用方法和细节与成员内部类相似,就不再赘述,在类中只可访问成员内部类的静态属性和方法,不可访问非静态的属性和方法,下面给出例子
public class StaticClass {
public static void main(String[] args) {
S s = new S();
S.S_1.say();
}
}
class S{
private int num = 100;
private static String name = "lyz";
//静态内部类,只能访问外部类静态成员
static class S_1{
public static void say(){
System.out.println("name = " + name);
}
}
}
运行结果如下
静态内部类中不能访问非静态的属性,符合java的语法规范,使用时idea会给出错误信息。
同样,静态内部类的使用也有两种方式
1.通过new静态类成员对象。
2.通过方法返回对象实例。
public class StaticClass {
public static void main(String[] args) {
//1.通过外部类.静态内部类直接创建对象
S.S_1 s_1 = new S.S_1();
s_1.say();
//2.编写方法返回对象实例
S.S_1 s_2 = new S().getInstance();
s_2.say();
}
}
class S{
private int num = 100;
private static String name = "lyz";
//静态内部类,只能访问外部类静态成员
static class S_1{
public static void say(){
System.out.println("name = " + name);
}
}
public S_1 getInstance(){
return new S_1();
}
}
运行结果如下
同样,静态内部类如果访问相同类名时仍然遵循就近原则,与成员内部类一样,访问外部时采用外部类.类名即可访问外部类的属性。
public class StaticClass {
public static void main(String[] args) {
S.S_1 s_1 = new S.S_1();
s_1.say();
}
}
class S{
private static int num = 100;
private static String name = "lyz";
//静态内部类,只能访问外部类静态成员
static class S_1{
private static int num = 200;
public static void say(){
System.out.println("静态内部类num = " + num);
System.out.println("外部类num = "+ S.num);
}
}
}
运行结果如下
作者能力有限,内容难免有所疏漏,欢迎读者及时批评指正。