一.内部类☆
1.基本介绍
一个类的内部完整的嵌套了另一个类结构,则被嵌套的类称为内部类,而嵌套内部类的类称为外部类
类的五大成员:属性、方法、构造器、代码块、内部类
内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类直接的关系
语法格式
class 类名{ //外部类
class 类名{ //内部类
}
}
内部类的分类
- 定义在外部类局部位置上(如:方法内部)
①局部内部类(有类名)
②匿名内部类(没有类名)☆ - 定义在外部类的成员位置上
①成员内部类(没有static修饰)
②静态内部类(有static修饰)
class A{
class B{ } //成员内部类
static class C{ } //静态内部类
public void test(){
class D{ } //局部内部类
new p1(){}; //匿名内部类(类)
new p2(){}; //匿名内部类(接口)
}
}
class p1{}
interface p2{}
2.局部内部类
局部内部类是定义在外部类的局部位置,比如方法、代码块,且有类名
语法格式
class 外部类名{
public void 方法名(){
class 内部类名{ }
}
}
使用细节
- 可以直接访问外部类的所有成员包括私有
- 不能添加访问修饰符,因为它是一个局部变量,局部变量是不能使用修饰符的,但可以使用final
- 内部类的作用域仅仅只在它所在的方法中或代码块中
- 外部类访问内部类成员,直接创建外部类对象,调用内部类所在的方法或代码块
- 局部内部类只能被方法内部访问(因为局部内部类的本质是一个局部变量)
- 如果外部类和局部内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
public static void main(String[] args) {
//细节四
A a = new A();
a.test2(); //方法test2中的内部类a的值=20
//细节五
// new B(); //其他类不能访问局部内部类
//细节六
a.test3();
}
}
class A{
private int a = 1;
private void p(){
System.out.println("外部类的方法");
}
public void test(){
class B{
//细节一
public void s(){
System.out.println(a);
p();
}
}
//细节二
// public class B1{} //错误
final class B1{} //正确
}
//细节三
public void test1(){
class B2{ }
B2 b2 = new B2(); //正确
}
// B2 b2 = new B2(); //错误
//细节四
public void test2(){
class B3{ int b = 20; }
B3 b2 = new B3(); //正确
System.out.println("方法test2中的内部类a的值="+b2.b);
}
//细节五
// new B(); //错误
//细节六
public void test3(){
class B4{
int a = 10; //与外部类属性重名,遵守就近原则
public void f(){
System.out.println("内部类属性a="+a); //10
//如果想在内部类访问外部类的属性则 外部类名.this.属性名
System.out.println("外部类属性a="+A.this.a);
}
}
B4 b4 = new B4();
b4.f();
}
}
3.匿名内部类☆☆☆
匿名内部类本质是内部类,该类没有名字,同时还是一个对象(在源码中和一些框架中经常用到)
说明:匿名内部类是定义在外部类的局部位置 如:方法中
语法格式:
class 类名{ //外部类
public void 方法名(){
new 类或接口(参数列表){ } //匿名内部类
}
}
使用场景
有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适,而且也免去了给它取名字的烦恼
也就是说当某一个对象只想使用一次时可以用匿名内部类,可以简化开发
快速入门
getClass()获取对象的运行类型
public class test1 {
public static void main(String[] args) {
demo demo = new demo();
demo.p();
//test...
//Anonymous的匿名内部类的运行类型=class com.test.demo$1
//name=张三
//Anonymous1的匿名内部类的运行类型=class com.test.demo$2
}
}
class demo{
public void p(){
//把这个匿名内部类赋值给A接口类型Anonymous
//匿名内部类在赋值给你Anonymous以后,这个匿名内部类就不存在了,不能用了,因为只能使用一次
/*
分析:
1.Anonymous的编译类型=A
2.Anonymous的运行类型=demo$1
3.其实底层代码就会创建匿名内部类
class demo$1 extends A{
@Override
public void test() {
System.out.println("test...");
}
}
*/
A Anonymous = new A() {
@Override
public void test() {
System.out.println("test...");
}
};
Anonymous.test(); //调用匿名内部类的方法
System.out.println("Anonymous的匿名内部类的运行类型="+Anonymous.getClass());
/*
分析:
1.Anonymous1的编译类型=B
2.Anonymous1的运行类型=demo$2
3.其实底层代码就会创建匿名内部类
class demo$2 extends B{ }
4.参数列表会传给 构造器
*/
B Anonymous1 = new B("张三"){
};
System.out.println("Anonymous1的匿名内部类的运行类型="+Anonymous1.getClass()); //getClass()获取对象的运行类型
}
}
interface A{
void test();
}
class B{
String name;
public B(String name) {
System.out.println("name="+name);
}
public void test(){ };
}
使用细节
- 匿名内部类既是一个类的定义,也是一个对象,所以它既有定义类的特征,也有创建对象的特征
- 可以直接访问外部类的所有成员,包括私有
- 不能添加访问修饰符,因为它是一个局部变量
- 作用域只能在定义它的方法或代码块中
- 外部其他类不能访问匿名内部类成员,因为他是一个局部变量
- 如果外部类和匿名内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
public static void main(String[] args) {
demo demo = new demo();
demo.p();
System.out.println("============");
demo.p1();
}
}
class demo{
private int a = 1;
private void demo1(){
System.out.println("外部类的方法!");
}
public void p1(){
//细节2
A b = new A() {
@Override
public void test() {
System.out.println("外部类属性a=" + a); //外部类属性
demo1(); //外部类方法
}
};
b.test();
}
public void p(){
//细节1,当匿名内部类是一个类的定义
A a = new A() {
@Override
public void test() {
System.out.println("匿名内部类是一个类的定义的test方法!");
}
};
a.test(); //动态绑定,运行类型则是demo$1
//细节1,当匿名内部类是一个对象
new A() {
@Override
public void test() {
System.out.println("匿名内部类是一个对象的test方法!");
}
}.test(); //也可以直接调用,匿名内部类本身也是返回对象
//细节6,如果匿名内部类属性与外部类属性重名时
new A() {
int a = 20;
@Override
public void test() {
System.out.println("匿名内部类属性a="+a); //就近原则 a=20
System.out.println("外部类属性a="+demo.this.a); //a=1
}
}.test();
}
}
class A{
public void test(){
System.out.println("A类的test方法!");
};
}
最佳实践
把匿名内部类当作实参直接传递,简洁高效
public class test1 {
public static void main(String[] args) {
//匿名内部类的方式,
Person person = new Person();
person.exercise(new motion() {
@Override
public void method() {
System.out.println("匿名内部类:跑步中...");
}
});
person.exercise(new motion() {
@Override
public void method() {
System.out.println("匿名内部类:跳绳中...");
}
});
//普通方法-硬代码的方式
Person1 person1 = new Person1();
person1.method();
Person2 person2 = new Person2();
person2.method();
}
}
interface motion{
void method();
}
class Person{
public void exercise(motion motion){ //接口类型
motion.method();
}
}
class Person1 implements motion{
@Override
public void method() {
System.out.println("普通方法:跑步中!!!");
}
}
class Person2 implements motion{
@Override
public void method() {
System.out.println("普通方法:跳绳中!!!");
}
}
4.成员内部类
语法格式
class 外部类名{
class 成员类名{
}
}
使用细节
- 可以直接访问外部类成员,包括私有的
- 可以添加访问修饰符(public、protected、默认、private),因为它就是外部类的一个成员
- 作用域跟外部类的其它成员一样,为整个类体
- 外部类访问成员内部类 访问方式:先创建对象,再访问
- 如果外部类和成员内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class test1 {
public static void main(String[] args) {
A a = new A();
a.test();
}
}
class A{
private int a = 1;
//细节二
public class B{
int a = 20;
//细节一
public void say(){
System.out.println("a="+a);
//细节五
System.out.println("成员内部类a="+a);
System.out.println("外部类成员a="+A.this.a);
}
}
public void test(){
//细节四 使用成员内部类
B b = new B();
b.say();
};
}
5.静态内部类
语法格式
class 外部类名{
static class 成员类名{
}
}
使用细节
- 可以直接访问外部类的所有静态成员,包含私有的(注意:不能访问非静态成员)
- 可以添加访问修饰符(public、protected、默认、private),因为它就是外部类的一个成员
- 作用域跟外部类的其它成员一样,为整个类体
- 外部其他类使用静态内部类,可以通过类名直接访问,前提满足访问权限
- 外部类访问静态内部类访问方式:
方法一:先创建对象,再访问
方法二:编写一个方法返回静态内部类的对象实例,再访问
方法三:编写一个静态方法返回静态内部类的对象实例,再访问 - 如果外部类和静态内部类的成员(属性或方法等)重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.成员)去访问
public class test1 {
public static void main(String[] args) {
//细节四 方法一
System.out.println("细节四 方法一");
A.B b = new A.B();
b.say();
//细节四 方法二
System.out.println("细节四 方法二");
A a = new A();
A.B b1 = a.getB();
b1.say();
//细节四 方法三
System.out.println("细节四 方法三");
A.B b11 = A.getB1();
b11.say();
}
}
class A{
private int a = 1;
private static int b = 1;
//细节二
public static class B{
int b = 20;
//细节一
public void say(){
// System.out.println(a);//错误,必须是静态成员
System.out.println("成员静态属性b="+b);
//细节五
System.out.println("静态内部类b="+b);
System.out.println("外部类成员b="+A.b);
}
}
//细节四 方法一
public void test(){
B b = new B();
b.say();
};
//细节四 方法二
public B getB(){
return new B();
}
//细节四 方法三
public static B getB1(){
return new B();
}
}