Java 内部类浅析

一、引言

由于目前是Android开发的实习生,在开发过程中发现越来越多自己知道但是真正去使用的时候却用不上的情况,比如内部类的使用上,所以在经过网上查找资料学习以及自己总结之后,特此发表一篇博文与大家分享,如有不当之处,万望指出。

二、内部类

内部类是指在一个外部类的内部再定义一个类,是一个编译时的概念,一旦编译成功,内部类与其外部类就会成为完全不同的两类,只是内部类的前面会冠以外部类的类名和$符号,如一个outer类内部定义了一个inner的内部类,那么编译完成后会生成outer.class和outer$inner.class两个类,因此内部类的成员变量与方法可以与外部类相同。

从内部类的定义上来看,其实内部类严重破坏了良好的代码结构,那么为什么还要使用内部类呢?因为内部类可以随意使用外部类的成员变量(包括私有的)而不用生成外部类对象,这也是内部类的唯一优点。

三、内部类的分类及示例

内部类分为成员内部类、局部内部类、静态内部类和匿名内部类。下面针对各个内部类进行介绍:

(1)成员内部类

作为外部类的一个成员存在,与外部类的属性、方法并列。成员内部类中可以访问外部类的所有成员,当外部类的变量与内部类的变量名重复时,使用外部类名.this.变量名可以对外部类的变量进行调用,如果没有重复时可直接使用变量名进行调用。在普通外部类方法中访问静态内部类可new出成员内部类对象进而直接调用其中的方法,而在静态外部类方法中需要先new出外部类对象,再调用外部类对象名.new 内部类的方式来获得成员内部类对象。

成员内部类中不能定义静态变量,因为成员内部类需要先创建了外部类,才能创建它自己的。

成员内部类可以使用外部类的私有成员和属性,同时其在外部类中定义了不可访问的属性,这样就在外部类中实现了比外部类的private还要小的访问权限。

示例代码如下:

/**
 *
 * @ClassName: MemberInnerClass
 * @Description: 成员内部类
 * @author ADAM
 * @date 2014年7月25日 上午9:20:28
 *
 */
public class MemberInnerClass {
	private int i = 0;

	public class Inner {// 成员内部类可加权限修饰符
		int i = 3;

		public void print() {
			System.out.println(i);// 输出为内部类的i,值为3
			System.out.println(this.i);// 输出为内部类的i,值为3
			System.out.println(MemberInnerClass.this.i);// 输出外部类的i,值为0
		}
	}

	public void print() {
		(new Inner()).print();// 外部类普通方法调用成员内部类直接new出内部类进行调用
	}

	public static void main(String[] args) {
		((new MemberInnerClass()).new Inner()).print();// 外部类静态方法中调用成员内部类首先new出外部类然后new出内部类进行调用
	}
}

(2)局部内部类

即在方法中定义的内部类,与局部变量类似,在局部内部类前不加修饰符public或private,其范围为定义它的代码块。局部内部类中不可定义静态变量,可以访问外部类(即方法)中的变量,但是变量必须是final。局部内部类与外部类的命名重名时的调用方法与成员内部类相同,访问局部内部类必须得先有外部类对象。

在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。要想使用局部内部类时需要生成外部类对象,对象再去调用方法,在方法中才能调用其局部内部内。通过内部类与接口达到了一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。

示例代码如下:

/**
 *
 * @ClassName: LocalInnerClass
 * @Description: 局部内部类
 * @author ADAM
 * @date 2014年7月25日 上午10:36:26
 *
 */
public class LocalInnerClass {
	private int j = 3;
	private int i = 2;

	public void test() {
		MemberInnerClass memberInnerClass = new MemberInnerClass();
// 若要访问其他类中的成员内部类只能当该成员内部类的修饰符为public才可
// 否则编译错误,即成员内部类可以再类内部实现比private还要小的权限
		memberInnerClass.new Inner();
		final int i = 0;
		class Inner {// 此处不得加上private等修饰符,否则编译错误
			int i = 1;

			public void print() {
				System.out.println(j);饰符,否则编译错误
				System.out.println(i);// 此时输出局部内部类的i,外部方法中的变量只能通过传参的形式进行调用
				System.out.println(LocalInnerClass.this.i);// 此时输出的是外部类中的i
			}
		}
		Inner inner = new Inner();// 局部内部类只能在方法内实例化并进行调用
		inner.print();
	}

	public static void main(String[] args) {
		(new LocalInnerClass()).test();
	}
}

局部内部类不仅可以定义在方法中还可以定义在作用域内。以下提供两个Thinking in Java的例子

定义在方法内:

public class Parcel4 {
    public Destination destination(String s) {
        class PDestination implements Destination {
            private String label; 

            private PDestination(String whereTo) {
                label = whereTo;
            } 

            public String readLabel() {
                return label;
            }
        }
        return new PDestination(s);
    } 

    public static void main(String[] args) {
        Parcel4 p = new Parcel4();
        Destination d = p.destination("Tasmania");
    }
} <span style="line-height: 1.3em; font-family: 'Courier New', monospace; background-color: inherit;"> </span>

定义在作用域里:

public class Parcel5 {
    private void internalTracking(boolean b) {
        if (b) {
            class TrackingSlip {
                private String id;
                TrackingSlip(String s) {
                    id = s;
                }
                String getSlip() {
                    return id;
                }
            }
            TrackingSlip ts = new TrackingSlip("slip");
            String s = ts.getSlip();
        }
    } 

    public void track() {
        internalTracking(true);
    } 

    public static void main(String[] args) {
        Parcel5 p = new Parcel5();
        p.track();
    }
} 

局部内部类也像别的类一样进行编译,只是作用域有所不同,只在该方法或者条件的作用域内才能使用,出了这些作用域则无法被使用。

(3)静态内部类

静态内部类也称为嵌套内部类,定义在类中,任何方法外,用static定义,静态内部类中可以定义静态或非静态的成员,其可用public、private等修饰符修饰,一般使用public修饰,方便调用,其只能访问外部类中的静态成员。外部类访问静态内部类中的静态成员时直接使用内部类.静态成员,访问静态内部类的非静态成员时先实例化静态内部类再通过对象访问。

生成一个静态内部类不需要外部类对象成员,这是与成员内部类的区别,同时普通内部类不能有static方法和属性,也不能包含嵌套类,静态内部类的对象可以直接生成:外部类.内部类 对象名= new 外部类.内部类()即可

注意:当类与接口(或者接口与接口)发生方法命名冲突时,必须使用内部类来实现。用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。

示例代码如下:

/**
 *
 * @ClassName: StaticInnerClass
 * @Description: 静态内部类
 * @author ADAM
 * @date 2014年7月25日 上午10:37:04
 *
 */
public class StaticInnerClass {
	private int i = 1;
	public static int j = 1;
	public int k = 0;

	public static class Inner {
		private int i = 0;
		private static int j = 0;// 可定义静态与非静态成员

		public static void print() {
//			System.out.println(k);// 编译错误,不得调用外部类中的非静态成员
			System.out.println(new StaticInnerClass().i);//访问外部类中的非静态成员变量需要先实例化外部类
			System.out.println(j);
			System.out.println(new StaticInnerClass().j);// 静态内部类使用外部类中的静态成员
		}
	}

	public static void main(String[] args) {
		Inner.print();// 外部类静态方法或者非静态方法调用静态内部类中的静态成员时直接内部类名.成员即可
		StaticInnerClass.Inner inner = new StaticInnerClass.Inner();// 静态内部类的实例化不需要先实例化外部类
		System.out.println(inner.i);// 访问静态内部类中的非静态成员时需要先实例化静态内部类
	}
}

通过内部类实现多继承示例代码如下:

/**
 *
 * @ClassName: Pencil
 * @Description: 笔类
 * @author ADAM
 * @date 2014年7月25日 上午10:42:59
 *
 */
public abstract class Pencil {
	public abstract void write();
}
/**
 *
 * @ClassName: Eraser
 * @Description: 橡皮擦类
 * @author ADAM
 * @date 2014年7月25日 上午10:43:28
 *
 */
public abstract class Eraser {
	public abstract void erase();
}
/**
 *
 * @ClassName: PencilWithEraser
 * @Description: 多继承类
 * @author ADAM
 * @date 2014年7月25日 上午10:43:53
 *
 */
public class PencilWithEraser {
	private MyPencil pencil = new MyPencil();
	private MyEraser eraser = new MyEraser();

	private class MyPencil extends Pencil {//继承笔类

		@Override
		public void write() {
			System.out.println("To Write");
		}

	}

	private class MyEraser extends Eraser {//继承橡皮擦类
		@Override
		public void erase() {
			System.out.println("To Erase");
		}

	}

	// 本类自己的方法,调用继承类中的方法
	public void write() {
		pencil.write();
	}

	public void erase() {
		eraser.erase();
	}

	public static void main(String[] args) {
		PencilWithEraser pencilWithEraser = new PencilWithEraser();
		pencilWithEraser.write();
		pencilWithEraser.erase();
	}
}

(4)匿名内部类

用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的重写或实现,也使用于只是为了得到一个对象实例,不需要知道其实际类型,此时类名是没有意义的,也不需要被使用到。

示例代码如下:

/**
 *
 * @ClassName: AnonymousInnerClass
 * @Description: 匿名内部类
 * @author ADAM
 * @date 2014年7月25日 上午10:38:25
 *
 */
public class AnonymousInnerClass {
	public void click(OnClickListener onClickListener) {
		System.out.println("click,click");
	}

	public static void main(String[] args) {
		AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass();
		anonymousInnerClass.click(new OnClickListener() {// 直接new出匿名内部类,不需要保存对象,一般用于继承其他类或是实现接口
					@Override
					public void onClick() {
						System.out.println("Inner Click");
					}
				});
	}
}

四、总结

由于目前还是处于学习阶段,对于内部类的使用最多的也是成员内部类和匿名内部类,所以对于诸如非常细致地去区分各个内部类的使用场景以及涉及到的更小的访问权限的作用等方面体会并不是很深刻,之后有更进一步的学习会补上,也希望看到这篇博文的朋友如果有一些其他的见解或者补充或者是推荐学习的资料也可以提出来,这篇博文也是借鉴网上各位大神以及百科的相关资料,再自己手动编码验证总结出来的,感恩各位大神,谢谢。

Java 内部类浅析

时间: 2024-10-25 01:41:11

Java 内部类浅析的相关文章

浅析总结 Java 内部类的一些使用与梳理

======================================================== 作者:qiujuer 博客:blog.csdn.net/qiujuer 网站:www.qiujuer.net 开源库:Genius-Android 转载请注明出处:http://blog.csdn.net/qiujuer/article/details/43282699 --学之开源,用于开源:初学者的心态,与君共勉! ================================

Java内部类

本文是<Java核心技术 卷1>中第六章接口与内部类中关于内部类的阅读总结. Java中的内部类(inner class)是定义在另一个类内部的类.那么内部类有什么用呢?这里主要由三个内部类存在的原因: 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据.即,如果类A中定义了类B,那么类B可以访问类A中的数据,甚至是私有数据,但类A不能访问类B中的私有数据: 内部类可以对同一个包中的其他类隐藏起来.在一个包中,定义一个类时,即使不加上访问权限关键词,这个类也是包内其他类可访问的,不

Java内部类:局部内部类(三)

Java内部类分为4个部分进行阐述,分别为概览.成员内部类.局部内部类和匿名内部类. 在本文中是Java内部类的局部内部类,主要讲局部内部类的概念和在使用局部内部的过程中,需要注意的一个细节. 1.局部内部类的概念 在一个类的方法内部定义另外一个类,那么另外一个类就称作为局部内部类. class OutterClass { void test() { class InnerClass//局部内部类 { } } } 在上述代码中,InnerClass定义在OutterClass的test方法的内部

Java内部类:匿名内部类(四)

Java内部类分为4个部分进行阐述,分别为概览.成员内部类.局部内部类和匿名内部类. 在本文中是Java内部类的匿名内部类,主要讲述匿名内部类的概念.匿名内部类的好处.匿名内部类的使用前提.和匿名内部类的应用场景. 1.匿名内部类的概念 没有类名的类就称作为匿名内部类 2.匿名内部类的好处 简化书写 3.匿名内部类的使用前提 必须存在继承或者实现关系才能使用 4.匿名内部类的应用场景 匿名内部类一般是用于实参 示例代码: package com.rk.innerclass; public cla

Java内部类小程序(成员内部类,静态内部类,匿名内部类)

1 /** 2 * 测试java内部类(成员内部类,静态内部类,匿名内部类) 3 * 局部内部类不常用,就不写了. 4 * @package :java05 5 * @author shaobn 6 * @Describe : 7 * @Time: 2015-9-6 下午8:32:38 8 */ 9 public class TestInner { 10 11 /** 12 * @author shaobn 13 * @Describe : 14 * @param args 15 * @Time

Java内部类的使用小结

内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. *内部类可以是静态static的,也可用public,default,protected和private修饰.(而外部顶级类即类名和文件名相同的只能使用public和default). 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类.对于一个名为outer的外部类和其内部定义的名为inner的内部类.编译完成后出现outer.class和outer$inner.class两类.所以内部类的成员变量/方法名可

java内部类和匿名内部类

内部类即是包含在类里面的又一个类. java内部类分为: 成员内部类.静态嵌套类.方法内部类.匿名内部类 . 内部类的共性 (1).内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 . (2).内部类不能用普通的方式访问.内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 . (3).内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 . 成员内部类

Java内部类的继承

Java内部类的构造器必须连接到指向其外围类对象的引用(构造内部类必须给它一个外部类对象的引用,内部类依赖于外部类对象),所以在继承内部类的时候,需要在导出类的构造器中手动加入对基类构造器的调用. 因为,在导出类实例化时,并不存在一个外围类对象,以让导出类的实例去连接到它. 所以,我们需要创建一个外围类,然后用一个特定的语法来表明内部类与外围类的关系. 在下例子中,需要给导出类InheritInner一个来自内部类的外围类中的引用.普通的继承,只需在导出类构造器中加入super();,而内部类则

【转】Java 内部类种类及使用解析

Java 内部类种类及使用解析 内部类Inner Class 将相关的类组织在一起,从而降低了命名空间的混乱. 一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分. Java中的内部类共分为四种: 静态内部类static inner class (also called nested class) 成员内部类member inner class 局部内部类local inner class 匿名内部类anonymous inner class 静态内部类Static