欢迎大家来到IT世界,在知识的湖畔探索吧!
在定义类的时候,我们一般把类定义成一个独立的程序单元。但是在某些情况下,我们会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,也可以称为嵌套类。包含内部类的类也被称为外部类,也可以称为宿主类。Java从JDK1.1开始引入内部类,内部类的主要作用如下:
1.内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中其他类访问该类。
2.内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部类的成员,同一个类成员之间可以相互访问。
3.匿名内部类适合用于创建那些仅需要一次使用的类。
4.外部类要访问内部类的成员,必须创建对象。
而根据出现的位置以及修饰的方式不同,我们也可以对内部类进行区别开来。
6.7.1成员内部类
如果把一个内部类定义的和成员变量、成员方法同级,则这个内部类就是一个成员内部类。
这里考虑一个问题,如果直接访问内部类的成员?
方式1:
class Student{
class EnglishStudent{
public void speak(){
System.out.println(“我会说英语!”);
}
}
}
class Test{
public static void main(String[] args){
Student.Englisthstudent se = new Student().new EnglishStudent();
se.speak();
}
}
欢迎大家来到IT世界,在知识的湖畔探索吧!
也就是说格式如下:外部类名.内部类名 对象名 = 外部类名.内部类名;但是一般来说,在实际开发中是不会这样使用的,因为一般内部类就是不让外界访问的。
方式2:
欢迎大家来到IT世界,在知识的湖畔探索吧!package com.langsin.test;
public class Student {
private String name = "zhangsan";
public int age = 25;
//============内部类开始=======================
class Action{
//没有什么特殊意义,就是一个内部类的成员变量
public String name = “wangwu”;
public int age = 26;
public String flag = "abc";
public void change(){
Student.this.name = "lisi";
Student.this.age = 35;
}
}
//=============内部类结束========================
public void run(){
Action action = new Action();
action.change();
System.out.println(this.name);
System.out.println(this.age);
}
public static void main(String[] args) {
Student stu = new Student ();
stu.run();
}
}
像上面这个代码一样,随便来个人就能把你的姓名和年龄给改掉,这样合适吗?很显然并不合适,那怎么办呢?我们可以用private关键字把这个内部类写成私有的。除了修改访问控制修饰符,还可以像上面的做法一样,我们可以把内部类的操作写在一个方法里边,而我们还可以给这个方法里的操作加一个判断,如果你是户籍人员,我让你改,这里不演示了。
6.7.1.1题目:
题1:要求补齐代码,输出30,20,10;
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(?);
System.out.println(?);
System.out.println(?);
}
}
}
class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
答案:num
this.num:通过this限定对象
Outher.this.num:通过外部类名限定this对象。
6.7.2 局部内部类
如果把一个内部类定义在方法里面定义,等同一个局部变量,则这个内部类就是一个局部内部类。
举例1:
欢迎大家来到IT世界,在知识的湖畔探索吧!package com.langsin.test;
public class Test {
public int a = 12;
public void run(){
//局部内部的开始
class InnerTest{
public int num = 5;
public void run(){
System.out.println(num);
System.out.println(a);
}
}
//局部内部类结束
InnerTest it = new InnerTest();
it.run();
}
public static void main(String[] args) {
Test te = new Test();
te.run();
}
}
在局部内部类中,可以直接访问外部类的成员,也能在局部位置创建内部类对象,通过对象调用内部类方法,来使用局部内部类的功能。
6.7.2.1面试题:局部内部类访问局部变量的注意事项?
package com.langsin.test;
public class Test {
public void run(){
final int num = 5;
class InnerTest{
public void run(){
System.out.println(num);
}
}
InnerTest it = new InnerTest();
it.run();
}
public static void main(String[] args) {
Test te = new Test();
te.run();
}
}
我们发现了从内部类中访问的局部变量,需要被声明为最终类型。这里我们主要看为什么要用final进行修饰。因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。(也就是说run方法调用完毕消失了,但是在堆内存中的it对象并没有立即消失(它是被GC机制扫描处理消失的),对象中依然使用着外边的变量,你让它变量立马消失可以吗?),为了让数据还能继续被使用,就用final修饰,这样,在堆内存里面存储的其实是一个常量值。既然是常量,你消失了,我在内存中存储的数据20,还是有数据在使用的。感兴趣的同学可以通过反编译工具可以看一下。
6.7.3 非静态内部类
定义内部类非常简单,只要把一个类放在另一个类内部定义即可。此处的“内部类”包括类中的任何位置,甚至在方法中也可以定义内部类,在方法中定义的内部类叫做局部内部类。
通常情况下,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与Field、方法、构造器和初始化块相似的类成员。
成员内部类分为:静态内部类和非静态内部类两种,使用static修饰的成员内部类就是静态内部类,没有使用static修饰的成员内部类就是非静态内部类。
因为内部类作为其外部类的成员,所以可以使用任意访问控制符:private、protected、public修饰的Field成员。
6.7.4 静态内部类
使用static修饰符来修饰内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。因此使用static修饰的内部类被称为静态内部类。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
举例1:
package com.langsin.test;
public class Car {
private static String name = "zhangsan";
public int age = 25;
static class Action{
public static String flag = "abc";
public String gender = "1";
public void change(){
Car.name = "lisi";
//下面这行代码编译报错
Car.this.age = 34;
}
}
public void run(){
Action action = new Action();
action.change();
System.out.println(name);
System.out.println(this.age);
System.out.println(Action.flag);
}
public static void main(String[] args) {
Car car = new Car();
car.run();
}
}
外部类不能直接访问静态内部类的实例成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。
举例2:
package com.langsin.test;
public class Test {
static class InnerTest{
public static int num = 1;
public int num2 = 5;
}
public void run(){
InnerTest.num = 4;
System.out.println(InnerTest.num); //4
InnerTest it = new InnerTest();
System.out.println(it.num); // 4
}
}
6.7.5 匿名内部类
匿名内部类的语法有些特别,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。因此匿名内部类适合创建那种只需要一次使用的类。
匿名内部类的格式如下:
new 父类构造器|实现接口(){
//匿名内部类的类体部分(重写方法)
}
匿名内部类必须继承一个父类,这个类可以是抽象类也可以是具体类,或实现一个接口,但最多只能继承一个父类,实现一个接口。
匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。它的一个本质是一个继承了该类或者实现了该接口的子类匿名对象。
匿名内部类不能定义构造器,因为匿名内部类没有类名,也就无法定义构造器,但是匿名内部类可以定义实例初始化块,通过初始化块来完成初始化操作。
使用方式1:
package com.langsin.test;
public class Test {
public int aa = 12;
public void run(InnerTest it){
System.out.println(it.num2);
it.run();
}
public static void main(String[] args) {
Test te = new Test();
te.run(new InnerTest(){
public void run(){
System.out.println(“aaaaaaaaaaaaaaaaa”);
}
});
}
}
abstract class InnerTest{
public int num2 = 5;
public abstract void run();
}
使用方式2:
interface Inter {
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
//一个方法的时候
/*
new Inter() {
public void show() {
System.out.println("show");
}
}.show();
*/
//二个方法的时候
/*
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show();
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show2();
*/
//如果我是很多个方法,就很麻烦了
//那么,我们有没有改进的方案呢?
Inter i = new Inter() { //多态
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerClassDemo6 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
使用方式3:
/*
匿名内部类在开发中的使用
*/
interface Person {
public abstract void study();
}
class PersonDemo {
//接口名作为形式参数
//其实这里需要的不是接口,而是该接口的实现类的对象
public void method(Person p) {
p.study();
}
}
//实现类
class Student implements Person {
public void study() {
System.out.println("好好学习,天天向上");
}
}
class InnerClassTest2 {
public static void main(String[] args) {
//测试
PersonDemo pd = new PersonDemo();
Person p = new Student();
pd.method(p);
System.out.println("--------------------");
//匿名内部类在开发中的使用
//匿名内部类的本质是继承类或者实现了接口的子类匿名对象
pd.method(new Person(){
public void study() {
System.out.println("好好学习,天天向上");
}
});
}
}
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/32916.html