内部类:
把类定义在其他类的内部,这个类就被称为内部类
举例:在类A中定义一个类B,类B就被成为内部类
内部类的访问特点:
1、内部类可以不用创建对象的访问外部类的成员,包括私有。
2、外部类要访问内部类的成员,必须创建对象。
内部类举例
package review.InnerDemo;
class Outer{
int num = 20;
class Inner{
int num = 10;
public void show(){
System.out.println(num); //打印10,访问内部类的成员变量num
System.out.println(Outer.this.num); //打印20,访问外部类的成员变量num
}
}
public void show(){
Inner i = new Inner(); //外部类访问内部的成员,需要创建内部类对象
System.out.println(i.num); //打印10,访问内部类的成员变量num
i.show(); //访问内部类的成员方法
System.out.println(num); //打印20,访问外部类的成员变量num
}
}
public class demo1 {
public static void main(String[] args) {
Outer o = new Outer();
o.show();
}
}
在这里Outer是外部类,Inner是内部类,可以看出来Inner类在Outer类的里面
内部类可以分为四种:成员内部类、局部内部类、匿名内部类、静态内部类
按照内部类在类中定义的位置不同,可以分为如下两种格式:
成员位置(成员内部类)
局部位置(局部内部类)
class Outer2{
//定义在成员位置,叫做成员内部类
class Inner{
//这是成员内部类
}
public void show(){
//定义在局部位置,叫做局部内部类
class Inner2{
//这是局部内部类
}
}
}
成员内部类
1、内部类可以访问外部类的成员,包括私有
2、正确的创建内部类的对象格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
成员内部类举例
package review.InnerDemo;
class Outer2{
int num = 20;
private int num1 = 30;
class Inner2{
int num = 10;
public void show(){
System.out.println(num);//打印10,访问内部类的成员变量
System.out.println(Outer2.this.num);//打印20,访问外部类的成员变量
System.out.println(Outer2.this.num1);//打印30,访问外部类的私有成员变量
//Outer2.this.Outer_show();用this这种方式也可以调用方法
}
}
public void Outer_show(){
Inner2 i = new Inner2();
System.out.println(i.num); //打印10,访问内部类的成员变量
System.out.println(num); //打印20,访问外部类的成员变量
}
}
public class demo2 {
public static void main(String[] args) {
Outer2 o = new Outer2();
o.Outer_show();
System.out.println("============");
//不能直接创建内部类的对象
//Inner2 i = new Inner2();这样做会报错
//需要这样创建对象,外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer2.Inner2 inner2 = new Outer2().new Inner2();
inner2.show();
}
}
结果为
一般来说,在实际开发中是不会这样使用的。因为一般内部类就是不让外界直接访问的。
所以我们会给内部类加上修饰符
private 为了保证数据的安全性
package review.InnerDemo;
class Computer{
private class Chip{
public void function(){
System.out.println("芯片工作");
}
}
public void show(){
Chip c = new Chip();
c.function();
}
}
public class demo3 {
public static void main(String[] args) {
Computer o = new Computer();
o.show();
//内部类加入了private权限修饰符之后,就不能被访问了
//Computer.Chip c = new Computer().new Chip();是错误的
}
}
芯片在电脑的里面,我们不希望芯片这个内部类被外界访问,所以用private修饰
这时我们只能在Computer类里面创建Chip类的对象,再由这个对象来调用成员变量或者成员方法。再像之前那样用外部类名.内部类名 对象名 = 外部类对象.内部类对象;的方法来创建内部类对象就不行了
那么有private修饰符,也有static修饰符
成员内部类加上一个static修饰符后变成静态内部类
格式为
class Outer{
static class Inner{
//静态内部类
}
}
静态内部类
static 为了让数据访问更方便
- 被静态修饰的成员内部类只能访问外部类的静态成员,无法访问非静态成员
- 静态内部类可以有静态成员,而非静态内部类则不能有静态成员(成员包括变量和方法)
- 非静态的成员内部类,成员只能是非静态的。
- 内部类被静态修饰后的方法有静态和非静态之分。他们的访问和不用静态是不一样的。
访问非静态方法:外部类名.内部类名 对象名 = new 外部类名.内部类名();
访问静态方法:上面创建的对象访问,或者外部类名.内部类名.方法名();
package review.InnerDemo;
class Computer1{
int num1 = 10;
static int num2 = 20;
public static class Chip1{
static int num3 = 30;
public static void show1(){ //内部类的静态方法
System.out.println(num2); //只能访问外部类的静态成员变量num2
System.out.println("静态方法");
}
public void show2(){ //内部类的非静态方法
System.out.println("非静态方法");
}
}
//外部类调用静态内部类的成员
public void test(){
System.out.println(Chip1.num3);
Chip1.show1();
Chip1 c = new Chip1();
c.show2();
}
}
public class demo4 {
public static void main(String[] args) {
//访问非静态方法
Computer1.Chip1 c = new Computer1.Chip1();
c.show2();
System.out.println("==========");
//访问静态方法
c.show1();
System.out.println("==========");
//访问静态方法
Computer1.Chip1.show1();
//调用外部类的test方法
System.out.println("==========");
Computer1 com = new Computer1();
com.test();
}
}
结果为
局部内部类
- 可以直接访问外部类的成员
- 可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
局部内部类存在于方法中。
package review.InnerDemo;
class Outer3{
int num1 = 10;
public void show(){
int num2 = 20;
class Inner3{
int num3 = 30;
public void show2(){
System.out.println(num3);
System.out.println(num2);
System.out.println(num1);
}
}
//num2 = 40; 这里无法修改num2的值
//jdk1.8之后会自动在局部方法上的局部变量添加final
//System.out.println(num2);在这里打印的结果是num2 = 20
//创建内部类对象,通过对象调用成员变量
Inner3 i = new Inner3();
i.show2();
}
}
public class demo5 {
public static void main(String[] args) {
Outer3 o = new Outer3();
o.show();
}
}
结果为
局部内部类和成员内部类的区别
- 局部内部类的作用范围在方法或者作用域之内
- 局部内部类不能用public或private访问说明符进行声明
package review.InnerDemo;
class Outer3{
public void show(){
class Inner3{
public void show2(){
//这两种方式调用外部类的方法,结果是一样的
Outer3.this.test();
test();
}
}
Inner3 i = new Inner3();
i.show2();
}
public void test(){
System.out.println("外部类方法");
//要注意,不能在这里创建内部类的对象,超出局部内部类的作用范围
//Inner3 i = new Inner3();
}
}
public class demo5 {
public static void main(String[] args) {
Outer3 o = new Outer3();
o.show();
}
}
结果为
匿名内部类
就是内部类的简化写法。
前提:存在一个类或者接口。这里的类可以是具体类也可以是抽象类。
格式:
new 抽象类名或者接口名() {
重写方法;
}
先来看看如果不适用匿名内部类,应该怎么写
public interface interDemo {
public abstract void show1();
public abstract void show2();
}
abstract class abstractDemo {
public abstract void test();
}
class Inter implements interDemo{
public void show1(){
System.out.println("show1");
}
public void show2(){
System.out.println("show2");
}
}
public class Ab extends abstractDemo{
public void test(){
System.out.println("test");
}
}
public class demo1 {
public void function(){
Inter i = new Inter();
i.show1();
i.show2();
Ab a = new Ab();
a.test();
}
public static void main(String[] args) {
demo1 d = new demo1();
d.function();
}
}
结果为
这样写无疑是比较麻烦的,现在再来看看,使用匿名内部类后怎么写
public interface interDemo {
public abstract void show1();
public abstract void show2();
}
abstract class abstractDemo {
public abstract void test();
}
package review.InnerDemo.anonymous;
public class demo1 {
public void function(){
interDemo i = new interDemo(){
public void show1(){
System.out.println("show1");
}
public void show2(){
System.out.println("show2");
}
};
i.show1();
i.show2();
abstractDemo a = new abstractDemo() {
@Override
public void test() {
System.out.println("test");
}
};
a.test();
}
public static void main(String[] args) {
demo1 d = new demo1();
d.function();
}
}
结果是
跟之前的结果一样,但代码简洁了许多
那么到具体的情景中,要怎么使用匿名内部类呢
首先定义一个接口,学生要学习,里面有两个抽象方法 读书read和背诵recite
public interface Study {
public abstract void read();
public abstract void recite();
}
package review.anonymous1;
public class demo1 {
//当接口做为参数传递的时候,实际上需要的是该接口实现类的对象
public void Student(Study s){
s.read();
s.recite();
}
public static void main(String[] args) {
demo1 d = new demo1();
d.Student(new Study() {
@Override
public void read() {
System.out.println("read");
}
@Override
public void recite() {
System.out.println("recite");
}
});
}
}
结果为