`

内部类

    博客分类:
  • java
 
阅读更多

首先了解内部类,顾名思义,将类嵌套在另一个类的内部,简单内部类:

public Student{
        private String name;//StbClass也可以使用name
        public StbClass{
                String getClass(){
                    name = "王大侠";
                }
        }
}

StbClass就是内部类。

 

=>使用内部类的原因:

1、内部类可以使用该类定义所在作用域中的数据,包括private修饰符在内的。

2、对同一包的其他类隐藏。

3、当要定义一个回调函数,而且只想编写少量代码来说,使用匿名内部类(后面)比较方便。(Java核心技术)

 

在外部类中初始化内部类,内部类的实例会绑定对应外部类的实例(除了内部类定义在静态方法中)。内部类的对象总有一个隐式引用,指向创建它的外部类对象。若是某个方法如getId中初始化内部类,那么这个内部对象将会绑定在执行该方法的实例上。

public class Student {
        //StbClass stbClass = new StbClass();
	private Integer id;	

	class StbClass{
		public void setId(){
			id = 8;
		}
 	}
	
	public Integer getId(){
		StbClass stbClass = new StbClass();
		stbClass.setId();
		return id;
	}
}

在外部类作用域之外实例化内部类,则需要特殊处理:

Student student = new Student();
Student.StbClass stbClass = student.new StbClass();

上面简写就是:OutClass.InnerClass。不过当StbClass设为私有,就不能再外部类外部实例化该类,只能在外部类内部声明。

 

内部类是一种编译器现象,与虚拟机无关。例如编译成外部类名+“$”符号+内部类名,而虚拟机却不知道。内部类访问外部类的私有数据存在一定的安全风险,即有可能通过附加在外围类所在包中的其他类访问到它们(有机会尝试)。

 

 

=>着重说明局部内部类、匿名内部类和静态内部类(static)。

 

1、局部内部类:

在一个类的方法中定义局部类,不能用public、private来修饰,作用域即在声明该局部类的代码块中。

	public Integer run(){
		class School{
			public void send(){
				id = 9;//访问外部类变量
			}
		}
		School school = new School();
		school.send();
		return id;
	}

School即为局部内部类,可以访问类的私有变量,也可以访问实例化在方法外部定义的简单外部类,不过它的作用域仅限于run方法中,即对外部完全隐藏。

 

局部类还可以访问方法参数,这些参数需要声明为final,所以只能引用:

	public Integer run(final String schoolName){
		class School{
			public void send(){
				id = 9;
				if("".equals(schoolName)){
					System.out.println("有啊");
				}
			}
		}
		School school = new School();
		school.send();
		return id;
	}

 

2、匿名内联类:

只创建一个类的对象,它允许在一个方法体内动态地定义没有命名的类的实现。

	public Integer run(){
		ISchool school = new ISchool() {
			public void send(){
				id = 9;
			}
		};
		return id;
	}
创建一个ISchool接口类的对象,需要实现的send方法在{}内部。

 

 

匿名内部类需继承扩展一个类或者实现一个接口。匿名内部类没有名称,意味着该类没有构造函数,不过可以将构造参数传给父类的构造函数(接口除外)。它的通常格式是:

new 父类名(构造参数)/接口名(){
     匿名内部类方法和数据
}
它比普通实例化对象多了{}。
public interface ISchool {
	public void send();
}
public Integer run(){
	ISchool school = new ISchool() {
                //重写接口方法
		public void send(){
			id = 9;
		}
	};
	school.send();
	return id;
}
public class School {
	private Integer i;
	public School(Integer i) {
		super();
		this.i = i;
	}
	public void send(Integer i){}
}

public Integer run(Integer i){
	School school = new School(i) {
                //扩展
		public void send(Integer a){
			id = a+9;
		}
	};
	school.send(i);
	return id;
}
上面的id返回之和。
上面的代码省去了一些编写接口实现类和子类的代码,也适用于编写少量代码的回调函数。在多线程应用中会大量使用匿名类。
		Thread thread = new Thread(){
			public void run(){
				System.out.println("运行中.");
			}
		};
		thread.start();
		
		Runnable runnable = new Runnable() {
			public void run() {
				System.out.println("运行中..");
			}
		};
		new Thread(runnable).start();
匿名内部类获取静态方法的类名,可以像new Object(){}.getClass().getEnclosingClass();,new Object(){}建立Object的一个匿名子类的一个匿名对象。

 

3、静态内部类 

当使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象,可以用static修饰,避免引用。

class Student{
     public static class Book{
	......	
     }
}

若在静态方法中使用到内部类,那么它必须声明成静态内部类。声明在接口中的内部类会自动成为static和public型。

 

下面的例子:

一个非静态的嵌套类的构造器,在编译的时候会将一个隐藏的参数作为它的第一个参数,这个参数表示了它的直接外围实例。当你在代码中任何可以让编译器找到合适的外围实例的地方去调用构造器的时候,这个参数就会被隐式地传递进去。但是,上述的过程只适用于普通的构造器调用,也就是不使用反射的情况。

当你使用反射调用构造器时,这个隐藏的参数就需要被显式地传递,这对于Class.newInstance方法是不可能做到的。要传递这个隐藏参数的唯一办法就是使用java.lang.reflect.Constructor。(考虑到从Java程序到class文件的映射的复杂度,请避免使用反射来实例化内部类。)

import java.lang.reflect.Constructor;

public class Outer {
	public static void main(String[] args) throws Exception {
		new Outer().greetWorld();
	}
	private void greetWorld() throws Exception {
		Constructor<Inner> constructor = Inner.class.getConstructor(Outer.class);//反射调用构造器需要注意的地方
		System.out.println(constructor.newInstance(Outer.this));
	}
	public class Inner {
		public String toString() {
			return "Hello world";
		}
	}
}

其实这里Inner实例并不需要一个外围的Outer实例,所以可以将Inner类型声明为静态的(static)。除非你确实是需要一个外围实例,否则你应该优先使用静态成员类(static member class)而不是非静态成员类。

即:

public class Outer {
	public static void main(String[] args) throws Exception {
		new Outer().greetWorld();
	}
	private void greetWorld() throws Exception {
		System.out.println(Inner.class.newInstance());
	}
	public static class Inner {
		public String toString() {
			return "Hello world";
		}
	}
}

结果打印出Hello World。

 

静态内部类(static)、非静态内部类(除了上面的特例)的区别:

(1)在于非静态内部类可以访问定义在外围类的实例变量,而静态内部类则不可以。

(2)非静态内部类完全封装在外围类中。虽然允许从外部代码中引用非静态内部类,不过不要那样做。静态内部类可以被外部代码使用和实例化,只要访问限定符号不是private。如静态内部类Entry(Map$Entry.class),遍历Map对象中的key-value对。在Map之外的上下文中,使用Map.Entry来引用这个类。

(3)静态内部类允许序列化,而非静态内部类不能序列化,因为他们可以访问外部实例变量,那么就意味着还要处理外部类的成员变量。

 

所以将内部类声明成静态的首要原因是别的类可以使用它,第二个原因是允许其序列化。

	public static class Book implements Serializable{
		private static final long serialVersionUID = 1L;
	}

 

分享到:
评论

相关推荐

    内部类分类及应用

    在使用匿名内部类时,要记住以下几个原则:匿名内部类不能有构造方法、匿名内部类不能是public、protected、private、static、只能创建匿名内部类的一个实例、匿名内部类不能定义任何静态成员、静态方法、一个匿名...

    内部类 匿名内部类 内部接口 对比说明

    内部类是Java编程语言中的一种特性,它允许我们在一个类的内部定义另一个类。这种设计模式在Android开发中尤其常见,因为它可以有效地管理代码和实现特定的功能。本文将详细探讨内部类、匿名内部类以及内部接口的...

    Java4Android 35_内部类和匿名内部类

    在Java编程语言中,内部类和匿名内部类是两种特殊类型的类,它们为代码的组织和功能实现提供了独特的灵活性。本教程"Java4Android 35_内部类和匿名内部类"深入探讨了这两个概念,旨在帮助开发者更好地理解和运用它们...

    java 内部类使用(内部匿名类)

    内部类分为几种类型,包括成员内部类、局部内部类、匿名内部类以及方法参数内部类。 1. **成员内部类**:成员内部类就像是外部类的一个普通成员,可以是静态或非静态的。非静态内部类拥有对外部类的引用,可以直接...

    java 匿名内部类的使用规范

    Java匿名内部类是Java语言中一个独特且强大的特性,它允许我们在不需要定义一个单独的类的情况下创建类的实例。这在处理回调、事件监听、单例模式以及其他需要短时间内定义一个简单类的情况时非常有用。本篇文章将...

    Java语法总结 - 内部类

    内部类可以分为四种:成员内部类、静态嵌套类、方法内部类和匿名内部类。 成员内部类 成员内部类是定义在外部类的成员变量中的一种内部类。它可以访问外部类的所有成员变量和方法,包括私有的变量和方法。成员内部...

    java 内部类 局部内部类 匿名类 实例代码

    本篇文章将深入探讨Java中的四种内部类:实例内部类、局部内部类、匿名类和静态内部类,并通过实例代码进行详细解析。 1. **实例内部类**:这是最常见的内部类形式,它在外部类的实例方法或成员位置定义。实例内部...

    java基础第七章内部类与异常类.doc

    Java 基础第七章内部类与异常类 Java 语言支持在一个类中定义另一个类,这样的类称做内部类。内部类和外嵌类之间存在着紧密的关系:内部类可以访问外嵌类的成员变量和方法,而外嵌类也可以使用内部类声明的对象作为...

    java内部类的讲解

    ### Java内部类详解 #### 一、内部类的分类与概念 Java的内部类机制是其强大特性之一,它允许类作为另一个类的成员存在,从而增强了代码的封装性和复用性。根据定义和作用域的不同,Java内部类主要分为四类: 1. ...

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存

    然而,不当使用Handler,尤其是结合匿名内部类或非静态内部类,可能导致内存泄漏和Native内存增加,这对应用性能和稳定性造成负面影响。 首先,我们要理解内存泄漏的概念。内存泄漏是指程序中已分配的内存没有被...

    内部类的分类及各自用法

    根据不同的应用场景和特性,内部类可以分为多种类型:成员内部类、局部内部类、静态内部类、匿名内部类。下面将详细介绍每种类型的内部类及其特点和使用方法。 #### 成员内部类 成员内部类(也称为非静态内部类)...

    反射私有内部类的例子

    ### 反射私有内部类的例子 #### 一、引言 在Java编程语言中,反射(Reflection)是一项强大的功能,允许程序在运行时检查和修改自身结构与行为。通过反射,可以动态地获取类的信息并操作其字段、方法以及构造器等。...

    JAVA 内部类 PPT

    Java内部类是Java语言的一个独特特性,它允许我们在一个类的内部定义另一个类。这种设计提供了更高级别的封装和组织代码的方式。以下是关于内部类及其相关知识点的详细说明: 1. **内部类基本语法** - **实例内部...

    内部类的使用

    首先,内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类就像其他成员变量一样,可以直接访问外部类的所有成员,包括私有成员。局部内部类只存在于某个方法内,它的作用范围更小,...

    java内部类详解

    内部类主要分为四种类型:静态内部类、成员内部类、局部内部类和匿名内部类。 1. 静态内部类(Static Inner Class) 静态内部类与普通的类类似,只是它们定义在外部类中,并且前面带有 `static` 关键字。它们不会...

    Java 深入理解嵌套类和内部类

    Java 嵌套类和内部类详解 Java 中的嵌套类和内部类是指在一个类的内部定义另一个类,这种类称为嵌套类(nested classes)。嵌套类有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,非静态嵌套类也即被称...

    Java内部类总结

    Java内部类主要包括以下几种类型:成员内部类(非静态内部类)、静态内部类(也称为静态嵌套类)、局部内部类和匿名内部类。 - **成员内部类**:这种类型的内部类是定义在外部类的一个成员位置上,它可以访问外部类...

    浅谈内部类与静态内部类的应用

    内部类可以分为四类:成员内部类、局部内部类、匿名内部类和静态内部类。在这里,我们重点关注成员内部类和静态内部类。 成员内部类,就像它的名字一样,是类的一个成员,与字段和方法处于同一级别。它可以访问外部...

    Java内部类(DOC)

    ### Java内部类(DOC)详解 #### 一、概述 Java内部类是Java语言中一个重要的概念,它指的是那些类定义被嵌套在其他类定义中的类。与之相对应的是顶层类,即那些类定义没有被嵌套在其他类中的类。内部类又可以...

    java代码笔记2010-06-01:Java内部类 静态内部类 局部内部类 明明内部类;StringBuffer reverse的使用;

    内部类可以分为四种类型:静态内部类、成员内部类(非静态内部类)、局部内部类和匿名内部类。 1. **静态内部类**: 静态内部类与普通的成员内部类不同,它不持有对外部类的引用。因此,可以像其他静态成员一样,...

Global site tag (gtag.js) - Google Analytics