内部类
内部类概念:在一个类的内部再定义一个完整的类.
特点: 编译之后可生成独立的字节码文件。
内部类可直接访问外部类的私有成员,而不破坏封装。
可为外部类提供必要的内部功能组件。
成员内部类
成员内部类:也称实例内部类
-
在类的内部定义,与实例变量、实例方法同级别的类。
-
外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
-
当外部类、内部类存在重名属性时,会优先访问内部类属性
-
成员内部类不能定义静态成员
1.成员内部类在实例层级——加载成员内部类中内容是在外部类对象被创建时。
package com.qf.day19.text;
/*
* 案例1,成员内部类
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
}
}
class Outer{
int a =10;//实例变量
public void m1() {//实例方法
}
//成员内部类(实例层级)
class Inner{
}
}
- 成员内部类对象的创建,依赖于外部类对象的创建。
成员内部类与外部类实例变量及方法是同一层级。
成员内部类可直接访问外部类实例变量 //1 私有成员变量也可直接访问,并不破坏封装//4。
成员内部类与外部类属性重名时,优先访问内部类属性//2。
若仍需获取外部类实例变量时则可通过//3(特殊、不具普适性)访问外部内实例变量。
/*
* 案例1,成员内部类
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
//1. Outer.Inner in = new Outer.Inner();
//2.实质上
Outer.Inner in = out.new Inner();
in.m2();
}
}
class Outer{
private int a =10;//实例变量//1 改为私有成员变量//4
public void m1() {//实例方法
}
//成员内部类(实例层级)
class Inner{
int a =20;
public void m2() {
System.out.println(a);//2
System.out.println("Class Inner m2()"+a);
System.out.println(Outer.this.a);//访问外部实例变量//3 特殊、不具普适性
}
}
}
3.成员内部类中不能定义静态成员//5,内部类属实例层级需要依赖于对象才能访问其值,但静态成员可用//6Outer.Inner.s;的方式来获取属性值,两者矛盾。不能定义静态成员,不能脱离外部类对象而独立存在。
/*
* 案例1,成员内部类
*/
public class TestInstanceInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
//1. Outer.Inner in = new Outer.Inner();
//2.实质上
Outer.Inner in = out.new Inner();
in.m2();
Outer.Inner.s;//6
}
}
class Outer{
private int a =10;//实例变量//1 改为私有成员变量//4
public void m1() {//实例方法
}
//成员内部类(实例层级)
class Inner{
int a =20;
static String s = "Null_kun";//5不能定义静态成员,不能脱离外部类对象而独立存在
public void m2() {
System.out.println(a);//2
System.out.println("Class Inner m2()"+a);
System.out.println(Outer.this.a);//访问外部实例变量//3
}
}
}
静态内部类
-
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
-
只能直接访问外部类的静态成员。(实例成员需实例化外部类对象)。
1.不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
//1访问类中的静态属性 类名.属性名 //2.访问静态内部类中属性,即静态内部类是外部类静态属性之一 //3创建内部类实例对象 //4使用静态内部类中的方法需先创建对象
public class TestStaticClass {
public static void main(String[] args) {
System.out.println(Outer.a);//1访问类中的静态属性 类名.属性名
System.out.println(Outer.Inner.b);//2.访问静态内部类中属性,即静态内部类是外部类静态属性之一
Outer.Inner in = new Outer.Inner();//3创建内部类实例对象
in.m2();//4使用静态内部类中的方法需先创建对象
}
}
class Outer{
static int a = 10;
static class Inner{ //静态内部类
static int b =20;
public void m2() {
System.out.println("Inner.m2()");
}
}
}
-
//5静态内部类只能直接访问外部类的静态成员,//6外部类静态成员私有也可直接访问。 //7静态内部类中并直接访问外部类中的实例变量,静态不能访问非静态实例变量。 //*比静态代码块功能更丰富。
public class TestStaticClass {
public static void main(String[] args) {
//System.out.println(Outer.a);//1访问类中的静态属性 类名.属性名
System.out.println(Outer.Inner.b);//2.访问静态内部类中属性,即静态内部类是外部类静态属性之一
Outer.Inner in = new Outer.Inner();//3创建内部类实例对象
in.m2();//4使用静态内部类中的方法需先创建对象
}
}
class Outer{
private static int a = 10;//6外部内静态成员私有
String s = "hello";//实例对象
static class Inner{ //静态内部类
static int b =20;
public void m2() {
System.out.println(Outer.a);//5.访问外部类静态属性
System.out.println("Inner.m2()");
System.out.println(Outer.s);//7访问外部类实例变量不行
}
}
}
局部内部类
-
定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
-
局部内部类访问外部类当前方法中的局部变量时,因无法保证变量的生命周期与自身相同,变量必须修饰为final。
-
限制类的使用范围。
1. //1定义在外部内的方法中,只有当方法执行,才会执行局部内部类,即方法执行完毕前建内部类对象
//2 只有创建外部类对象并执行内部类所在的方法,才执行局部内部类中代码。
//3.局部内部类中访问外部类的实例成员
//4.局部内部类中访问内部类的实例成员
//5.局部内部类访问外部类的局部变量
*//6 给m1方法中局部变量赋值,访问局部变量报错。JDK8以前版本中,int b 就会编译错误,必须将其修饰为final,JDK8会隐式加上final。
public class TestLocalInner {
public static void main(String[] args) {
Outer out = new Outer();
out.m1();//2 只有创建外部类对象并执行内部类所在的方法
}
}
class Outer{
int a =10;//实例变量
public void m1() {//外部类实例方法
int b =20;//局部变量
//b=88;//6.赋值 变量b必须是final修饰的常量
class Inner{//局部内部类
int c =30;
public void m2() {
System.out.println(Outer.this.a);//3.访问外部类的实例成员
System.out.println(this.c);//4.访问内部类的实例成员
System.out.println(b);//5.局部内部类访问外部类的局部变量
System.out.println("Inner m2()");
}
}
Inner in = new Inner(); //1
System.out.println(in.c);
in.m2();
}
public void m3() {}
}
- 存活周期JVM栈<Heap堆<方法区,局部内部类在内存中无对象或子类了才会回收。Inner对象在方法内的变量就必须在。
3.局部内部类继承接口。验证在外部实例方法结束后依然能存储局部变量值,若不加final局部变量生命周期早已结束。
public class TestLocalInner {
public static void main(String[] args) {
Outer out = new Outer();
out.m1();//只有创建外部类对象并执行内部类所在的方法
System.out.println(out.p);
out.p.print();
}
}
class Outer{
printable p=null;
int a =10;//实例变量
public void m1() {//外部类实例方法
int b =20;//局部变量
class Inner implements printable{//局部内部类
public void print() {
System.out.println(b);//局部内部类访问外部类的局部变量
}
}
p= new Inner();
}
}
interface printable{
public void print();
}
4.限制类的使用范围
4.1例如:若实现分班,但依然无法规避家长直接new教师,因为此时校方的内部规则,仍然是公开类。教师信息没有对外界隐藏所以家长可自己new
public class TestInnerLocalForApply {
public static void main(String[] args) {
//学校开设新班
/*1.
Teacher teacher = new AdvancedTeacher();//家长提出意见需要高级教师
teacher.teach();//问题就是校方没办法提供如此多的高级教师
*/
//校方出台了内部规则(按照班级的奇偶编号进行均匀分派,奇数初级,偶数高级)
Teacher t =School.getTeacher(1);
t.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用静态方法,无需new School
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new BeginnerTeacher();
}else {
currentTeacher = new AdvancedTeacher();
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}
class BeginnerTeacher extends Teacher{
@Override
public void teach() {
System.out.println("初级老师在上课");
}
}
class AdvancedTeacher extends Teacher{
@Override
public void teach() {
System.out.println("高级老师在上课");
}
}
4.2 初高级教师类定义在getTeacher方法中。利用抽象类实现高级封装,隐藏类的信息。
public class TestInnerLocalForApply {
public static void main(String[] args) {
//学校开设新班
/*1.
Teacher teacher = new AdvancedTeacher();//家长提出意见需要高级教师
teacher.teach();//问题就是校方没办法提供如此多的高级教师
*/
//校方出台了内部规则(按照班级的奇偶编号进行均匀分派,奇数初级,偶数高级)
Teacher t =School.getTeacher(1);
t.teach();
Teacher t1 =School.getTeacher(2);
t1.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用静态方法,无需new School
class BeginnerTeacher extends Teacher{
@Override
public void teach() {
System.out.println("初级老师在上课");
}
}
class AdvancedTeacher extends Teacher{
@Override
public void teach() {
System.out.println("高级老师在上课");
}
}
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new BeginnerTeacher();
}else {
currentTeacher = new AdvancedTeacher();
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}
匿名内部类
- 没有类名的局部内部类(一切特征都与局部内部类相同)
- 必须继承一个父类或者实现一个接口
- 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象(类信息只用到一次)
- 优点:减少代码量,书写思路流程。(编程思路可方便new对象)
- 缺点:可读性较差
例如4.3:将初高级教师的类和其中实现以及创建此类合并,修改4.2中实例匿名内部类。
public class TestInnerLocalForApply {
public static void main(String[] args) {
//学校开设新班
/*1.
Teacher teacher = new AdvancedTeacher();//家长提出意见需要高级教师
teacher.teach();//问题就是校方没办法提供如此多的高级教师
*/
//校方出台了内部规则(按照班级的奇偶编号进行均匀分派,奇数初级,偶数高级)
Teacher t =School.getTeacher(1);
t.teach();
Teacher t1 =School.getTeacher(2);
t1.teach();
}
}
class School{
public static Teacher getTeacher(int classNo) {//使用静态方法,无需new School
Teacher currentTeacher = null;
if(classNo%2 !=0) {
currentTeacher = new Teacher() {
@Override
public void teach() {
System.out.println("初级老师在上课");
}
};
}else {
currentTeacher = new Teacher() {
@Override
public void teach() {
System.out.println("高级老师在上课");
}
};
}
return currentTeacher;
}
}
abstract class Teacher{
public abstract void teach();
}