我们在利用面向对象描述事物的时候,之前我们一直都是一个类名,然后里面包含它的成员方法,成员属性还有构造方法三部分,比如创建一个人类,里面的属性大多是身高、体重、姓名等,我们用一个变量进行描述,但是事实上事物并不是都是那么的简单,比如我们想描述人类中的心脏属性,我们没办法只用一个变量就描述它的性质,只能用一个类来描述它。但是这个类又是人类的一个属性,所以,我们引入了内部类的这个概念,作为一个类的组成部分来进行对类更加详细的描述。
内部类
概念:定义在内部的类,就是内部类,可以定义在类的内部,也可以定义方法的内部。
根据定义的位置不同可以分为:成员内部类、局部内部类
成员内部类:
- 普通的成员内部类
- 私有的成员内部类
- 静态的成员内部类
根据表示的方式,可以分为:有名字的内部类、匿名内部类
普通的成员内部类
- 定义在成员位置上的类,就是成员内部类
- 定义格式 class 类名{内部类的成员}
- 成员内部类的访问说明
- 内部类可直接访问外部类的成员,包括私有的。
- 外部类也可以访问内部类的成员,必须先创建内部类的对象
- 在外部其它类中,创建内部类的对象格式:外部类名.内部类名 对象名 = new 外部类().new 内部类();
代码示例:
//外部其他类
public class 成员内部类 {
public static void main(String[] args) {
Body b = new Body();
b.test();
Body.Heart bh = new Body().new Heart();
bh.show();
Body.Heart.DongMai bhd = new Body().new Heart().new DongMai();
bhd.bouns();
}
}
//外部类
class Body{
private double height = 170.0;
//内部类
class Heart{
int beats = 90;
double height = 140;
class DongMai{
public void bouns() {
System.out.println("我是类中类中类");
}
}
public void show() {
System.out.println("扑通扑通的跳动"+beats+"次,身高:"+Body.this.height);
}
}
public void test() {
Heart h = new Heart();
h.show();
}
}
输出结果:
扑通扑通的跳动90次,身高:170.0
扑通扑通的跳动90次,身高:170.0
我是类中类中类
注意事项:
①内部类可以嵌套,内部类还可以创建内部类。
②当内部类中的成员变量和外部类中的成员变量重名的时候,调用内部类的成员变量利用this关键字,调用外部类中的成员变量用:外部类名.this.成员变量。
③在外部其他类中单独创建一个内部类的对象的格式为:外部类名.内部类名 对象名 = new 外部类().new 内部类();
私有的成员内部类
- 也是一个成员内部类,在成员内部类前面加上一个private关键字
- 访问方式说明
在外部类以外,不能直接访问外部类中的私有成员内部类。但是可以间接的访问,可以在外部类中,定义一个访问私有成员内部类的公共方法,让外界可以调用公共的方法,间接地访问外部类中的私有成员内部类。这里的概念就和成员变量一样,都是需要提供公共方法进行访问。
public class 私有的成员内部类 {
public static void main(String[] args) {
Body1 b1 = new Body1();
b1.test1();
}
}
class Body1{
private double weight = 60.0;
//私有的成员内部类
private class Face{
String eyes = "黑色";
public void show() {
System.out.println("你"+eyes+"的眼睛"+"重达"+weight+"公斤");
}
}
public void test1() {
Face f= new Face();
f.show();
}
}
输出结果:
你黑色的眼睛重达60.0公斤
静态内部类
也是一个内部类,在成员内部类加上static修饰。
特点:
- 当静态内部类想要访问外部类成员时。要么给外部类成员加上static修饰,要么在内部类方法中创建一个外部类的对象。
- 内部类是外部类的静态成员,可以通(外部类.内部类)方式直接访问,而不需要创建外部类对象,这是在静态内部类里面所有属性和方法都是静态的情况下。
- 因为其他的静态成员都随着类的加载就加载了,静态内部类中的非静态成员,需要等着对象的创建才会加载,所以静态内部类中的非静态成员需要等着所在内部类的对象的创建才能被调用。
总结:
静态内部类里面的成员如果是静态的,那么可以直接利用类名进行访问,如果是非静态的,就必须创建对象过后才能够进行访问。
所以,一个类是否需要创建对象,不取决于这个类是否是静态的,而是取决于这个类的成员是否是静态的。
代码示例:
public class Demo03 {
public static void main(String[] args) {
Body2 b =new Body2();
b.test();
//静态内部类的对象的创建过程
Body2.Fei g = new Body2.Fei();
System.out.println(Body2.Fei.color);
g.show();
Body2.Fei.show();
}
}
class Body2{
private double height = 179.0;
//静态内部类
static class Fei{
static String color = "red";
public static void show() {
//静态内部类访问外部类成员,要么创建外部类对象,要么外部成员加上static
Body2 b2 = new Body2();
System.out.println(color+"..."+b2.height);
}
}
public void test() {
// Fei f =new Fei();
// f.show();
// 如果说内部类是外部类的静态成员,可以通过外部类.内部类方式直接访问。而不需要创建外部类对象。
Body2.Fei.show();
}
}
输出结果:
red...179.0
red
red...179.0
red...179.0
局部内部类
定义在方法中的内部类
访问特点:
方法中的局部变量,外界都没有办法访问到,所以在方法中定义的内部类,外界也没有办法访问到
解决方案:在方法内部,创建局部内部类的对象,调用对象的方法,间接访问局部内部类中的成员。
代码示例:
public class 局部内部类 {
public static void main(String[] args) {
breath();
}
public static void breath() {
int f= 30;
//局部内部类
class Feei{
String color = "red";
public void show() {
System.out.println("颜色是"+color+"外部方法的变量f="+f);
}
}
// 创建局部内部类的对象
Feei fi = new Feei();
// 调用局部内部类的方法
fi.show();
}
}
输出结果:
颜色是red外部方法的变量f=30
匿名内部类
没有名字的内部类
前提:继承一个类或者实现一个接口
格式:
new 父类的类名或者接口名称(){
父类或者接口中的方法重写
};
本质:创建了一个类的子类对象、接口的实现类对象。所以这里说着名字是一个类,其实这里已经不是一个类了,这里确确实实的是一个类,不过是在声明的时候,又重写了父类或者接口中的所有方法,变成了一个独特的有着自己的方法的对象。因为没有名字,所以叫做匿名内部类。作为一个对象, 可以调用自己的方法。代码示例:
public class 匿名内部类 {
public static void main(String[] args) {
//3.创建实现类对象
InterImp1 ii = new InterImp1();
ii.method();
//匿名内部类
new Inter() {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("noName method run...");
}
}.method();
}
}
// 1.接口
interface Inter{
void method();
}
//实现类
class InterImp1 implements Inter{
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("interimp1 method run...");
}
}
输出结果:
interimp1 method run...
noName method run...
如果观察匿名内部类的形式,我们可以发现是new了一块空间,存储了一个对象的所有属性和内容。那么我们给它添加一个索引呢。
代码示例:
public class 匿名内部类 {
public static void main(String[] args) {
//3.创建实现类对象
InterImp1 ii = new InterImp1();
ii.method();
//匿名内部类
Inter iii = new Inter() {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("noName method run...");
}
};
iii.method();
}
}
// 1.接口
interface Inter{
void method();
}
//实现类
class InterImp1 implements Inter{
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("interimp1 method run...");
}
}
输出结果:
interimp1 method run...
noName method run...
这时,如果匿名内部类中有其他的方法,我们也可以直接利用引用来进行调用了,这里是利用了多态的思想。
匿名内部类是为了简便的完成某个接口的实现,所以类或者接口中有方法不超过3个,可以使用匿名内部类,再多的时候,就不如创建一个实现类方便了。