java基础(八)——内部类

【Java基础知识 16】java内部类使用场景 Java基础教程系列,打造精品专栏。 阅读详情

1.什么是内部类?

        将一个类定义在另一个内的内部,也就是嵌套在另一个类里面,这就是内部类(可以看下面的代码,Inner类和StaticInner就是Outer的内部类)。其实也可以把内部类看做一个类的普通成员,类似成员变量,成员方法。


2.内部类长什么样子?怎么定义?怎么调用?

        内部类跟普通类一样,只不过它是定义在另一个类的内部,可以用public, protected, default, private这几个修饰符修饰(前面说了,可以把内部类当普通成员看待,那么当然也能用这几个修饰符了,可以参考另一篇文章java基础(四)——访问控制符)。看代码

package com.xupk.inner.demo;


public class Outer {
	
	int i = 1;
	static int j = 10;
	
	//普通内部类可当做Outer类的普通成员
	class Inner{
	}
	
	//静态内部类可当作Outer类的静态类成员
	static class StaticInner{
		
	}
	
	//普通方法分别访问两个内部类,相当于普通方法访问两个类成员
	public void access(){
		i = 2;//普通变量
		j = 9;//静态变量
		Inner i = new Inner();//对于普通内部类,可以直接访问
		StaticInner s = new StaticInner();//普通方法肯定可以访问到类成员
	}
	
	//静态方法
	public static void main(String[] args) {
		Outer o = new Outer();
		
		int oi = o.i;//普通成员变量需要通过实例访问
		Inner i2 = o.new Inner();//类的静态方法访问普通成员,必须通过类的实例来访问
		/***
		 * 下面这语句会报错:
		 * 没有任何类型 Outer 的外层实例可访问。必须用类型 Outer 的外层实例
		 * (例如,x.new A(),其中 x 是 Outer 的实例)来限定分配。
		 * Inner i = new Inner();//类的静态方法不能直接访问类的普通成员
		 */
		
		Outer.j = 8;//类成员可以直接访问,不需要通过实例
		StaticInner i3 = new StaticInner();//类的静态方法可以直接访问类的静态成员
	}

}

3.静态内部类的加载顺序是怎么样的?

        首先我们知道,类加载时有加载、验证、准备、解析、初始化等阶段;那么初始化阶段,就是按代码出现的顺序先执行类的静态成员赋值语句和静态代码块,然后再执行静态方法。静态内部类会在其外部类加载的时候也把它加载进去吗?首先得了解一下,触发类初始化的5个条件(可以参考:初探java虚拟机类加载机制(零)——概述),我们发现下面代码中,并没有触发内部类的初始化,因为它不满足上面5个条件中的任意一个,所以,在外部类加载的时候,内部类并不会自己加载。看代码示例:

package com.xupk.inner.demo;

public class ClzInitTest {
	
	private static int i = 10;
	static{
		System.out.println("=============outer static code start===================");
		System.out.println("outer class load……");
		System.out.println("i=:"+i);
		System.out.println("=============outer static code end===================");
	}
	
	
	//静态内部类
	static class Inner{
		private static int i = 1;
		static{
			System.out.println("===================inner static code start================");
			System.out.println("inner class load……");
			System.out.println("i=:"+i);
			
		}
		
		static void init(){
			System.out.println("inner method load");
		}
		
		static{
			System.out.println("===================inner static code end==================");
		}
	}
	
	
	public static void main(String[] args) {
		//什么也不做
	}

}
输出如下:

=============outer static code start===================
outer class load……
i=:10
=============outer static code end===================
        可见,当外部类加载的时候,并没有加载内部类。再回头看看主动触发类初始化的5个条件,我们调用一个静态内部类的静态方法,应该是能触发内部类的初始化才对。实验一下,把上面的main方法改一下,看代码:

public static void main(String[] args) {
		Inner.init();
	}
输出如下:
=============outer static code start===================
outer class load……
i=:10
=============outer static code end===================
===================inner static code start================
inner class load……
i=:1
===================inner static code end==================
inner method load
        首先会加载外部类的静态代码块,然后main方法调用了静态内部类的静态方法init(),所以会触发Inner类的初始化,这时候初始化顺序是跟普通类初始化顺序一样的:顺序执行静态代码块和静态成员变量赋值语句,然后执行静态方法。

        这里有个典型的例子,就是单例模式的设计。JVM内部的机制能够保证:当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,会触发SingleTon的初始化,然后在该方法内访问StaticClassLazy这个内部类的静态变量instance时,会触发这个内部类的初始化,所以JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就能保证单例的安全实现。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题

package com.xupk.inner.demo;

public class SingleTon {
	
	//私有化构造方法
	private SingleTon(){
	}
	
	//利用类加载的线程是互斥的机制来保证加载这个内部类安全加载
	private static class StaticClassLazy{
		//类的静态变量只加载一次来保证单例
		private static SingleTon instance = new SingleTon();
	}
	
	//外部获取实例的方法
	public static SingleTon getInstance(){
		return StaticClassLazy.instance;
	}

}

4.在哪里用到内部类?

        LinkedList里面就使用了大量的内部类,比如Entry(jdk1.7后改为Node了)。下面引用一篇文章来说明一下内部类的应用场景(转自:http://blog.youkuaiyun.com/hivon/article/details/606312#insertcode)

场景一:当某个类除了它的外部类,不再被其他的类使用时
我们说这个内部类依附于它的外部类而存在,可能的原因有:1、不可能为其他的类使用;2、出于某种原因,不能被其他类引用,可能会引起错误。等等。这个场景是我们使用内部类比较多的一个场景。下面我们以一个大家熟悉的例子来说明。
在我们的企业级Java项目开发过程中,数据库连接池是一个我们经常要用到的概念。虽然在很多时候,我们都是用的第三方的数据库连接池,不需要我们亲自来做这个数据库连接池。但是,作为我们Java内部类使用的第一个场景,这个数据库连接池是一个很好的例子。为了简单起见,以下我们就来简单的模拟一下数据库连接池,在我们的例子中,我们只实现数据库连接池的一些简单的功能。如果想完全实现它,大家不妨自己试一试。
首先,我们定义一个接口,将数据库连接池的功能先定义出来,如下:
public interface Pool extends TimerListener
{
        //初始化连接池
        public boolean init();
        //销毁连接池
        public void destory();
        //取得一个连接
        public Connection getConn();
        //还有一些其他的功能,这里不再列出
        ……
}
有了这个功能接口,我们就可以在它的基础上实现数据库连接池的部分功能了。我们首先想到这个数据库连接池类的操作对象应该是由Connection对象组成的一个数组,既然是数组,我们的池在取得Connection的时候,就要对数组元素进行遍历,看看Connection对象是否已经被使用,所以数组里每一个Connection对象都要有一个使用标志。我们再对连接池的功能进行分析,会发现每一个Connection对象还要一个上次访问时间和使用次数。
通过上面的分析,我们可以得出,连接池里的数组的元素应该是由对象组成,该对象的类可能如下:
public class PoolConn
{
        private Connection conn;
        private boolean isUse;
        private long lastAccess;
        private int useCount;
        ……
}
下面的省略号省掉的是关于四个属性的一些get和set方法。我们可以看到这个类的核心就是Connection,其他的一些属性都是Connection的一些标志。可以说这个类只有在连接池这个类里有用,其他地方用不到。这时候,我们就该考虑是不是可以把这个类作为一个内部类呢?而且我们把它作为一个内部类以后,可以把它定义成一个私有类,然后将它的属性公开,这样省掉了那些无谓的get和set方法。下面我们就试试看:
public class ConnectPool implements Pool
{
	//存在Connection的数组
	private PoolConn[] poolConns;
	//连接池的最小连接数
	private int min;
	//连接池的最大连接数
	private int max;
	//一个连接的最大使用次数
	private int maxUseCount;
	//一个连接的最大空闲时间
	private long maxTimeout;
	//同一时间的Connection最大使用个数
	private int maxConns;
	//定时器
	private Timer timer;
	public boolean init()
	{
		try
		{
			……
			this.poolConns = new PoolConn[this.min];
			for(int i=0;i<this.min;i++)
			{
				PoolConn poolConn = new PoolConn();
				poolConn.conn = ConnectionManager.getConnection();
				poolConn.isUse = false;
				poolConn.lastAccess = new Date().getTime();
				poolConn.useCount = 0;
				this.poolConns[i] = poolConn;
			}
			……
			return true;
		}
		catch(Exception e)
		{
			return false;
		}
	}
	……
	private class PoolConn
	{
		public Connection conn;
		public boolean isUse;
		public long lastAccess;
		public int useCount;
	}
}
因为本文不是专题来讲述数据库连接池的,所以在上面的代码中绝大部分的内容被省略掉了。PoolConn类不大可能被除了ConnectionPool类的其他类使用到,把它作为ConnectionPool的私有内部类不会影响到其他类。同时,我们可以看到,使用了内部类,使得我们可以将该内部类的数据公开,ConnectionPool类可以直接操作PoolConn类的数据成员,避免了因set和get方法带来的麻烦。
上面的一个例子,是使用内部类使得你的代码得到简化和方便。还有些情况下,你可能要避免你的类被除了它的外部类以外的类使用到,这时候你却不得不使用内部类来解决问题。
 
场景二:解决一些非面向对象的语句块
这些语句块包括if…else if…else语句,case语句,等等。这些语句都不是面向对象的,给我们造成了系统的扩展上的麻烦。我们可以看看,在模式中,有多少模式是用来解决由if语句带来的扩展性的问题。
Java编程中还有一个困扰我们的问题,那就是try…catch…问题,特别是在JDBC编程过程中。请看下面的代码:
……
try
{
	String[] divisionData = null;
	conn = manager.getInstance().getConnection();
	stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
	stmt.setLong(1 ,productId.longValue() );
	stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
	stmt.execute();
	ResultSet rs = stmt.getCursor(2);
	int i = 0 ;
	String strDivision = "";
	while( rs.next() )
	{
		strDivision += rs.getString("DIVISION_ID") + "," ;
	}
	int length = strDivision.length() ;
	if(length != 0 )
	{
		strDivision = strDivision.substring(0,length - 1);
	}
	divisionData = StringUtil.split(strDivision, ",") ;
	map.put("Division", strDivision ) ;
	LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
}catch(Exception e)
{
	LoggerAgent.error("GetHeaderData", "getDivisionData",
			"SQLException: " + e);
	e.printStackTrace() ;

}finally
{
	manager.close(stmt);
	manager.releaseConnection(conn);
}
这是我们最最常用的一个JDBC编程的代码示例。一个系统有很多这样的查询方法,这段代码一般分作三段:try关键字括起来的那段是用来做查询操作的,catch关键字括起来的那段需要做两件事,记录出错的原因和事务回滚(如果需要的话),finally关键字括起来的那段用来释放数据库连接。
我们的烦恼是:try关键字括起来的那段是变化的,每个方法的一般都不一样。而catch和finally关键字括起来的那两段却一般都是不变的,每个方法的那两段都是一样的。既然后面那两段是一样的,我们就非常希望将它们提取出来,做一个单独的方法,然后让每一个使用到它们的方法调用。但是,try…catch…finally…是一个完整的语句段,不能把它们分开。这样的结果,使得我们不得不在每一个数据层方法里重复的写相同的catch…finally…这两段语句。
既然不能将那些讨厌的try…catch…finally…作为一个公用方法提出去,那么我们还是需要想其他的办法来解决这个问题。不然我们老是写那么重复代码,真是既繁琐,又不容易维护。
我们容易想到,既然catch…finally…这两段代码不能提出来,那么我们能不能将try…里面的代码提出去呢?唉哟,try…里面的代码是可变的呢。怎么办?
既然try…里面的代码是可变的,这意味着这些代码是可扩展的,是应该由用户来实现的,对于这样的可扩展内容,我们很容易想到用接口来定义它们,然后由用户去实现。这样以来我们首先定义一个接口:
public interface DataManager
{
        public void manageData();
}
我们需要用户在manageData()方法中实现他们对数据层访问的代码,也就是try…里面的代码。
然后我们使用一个模板类来实现所有的try…catch…finally…语句的功能,如下:
public class DataTemplate
{
	public void execute(DataManager dm)
	{
		try
		{
			dm.manageData();
		}
		catch(Exception e)
		{
			LoggerAgent.error("GetHeaderData", "getDivisionData",
					"SQLException: " + e);
			e.printStackTrace() ;

		}finally
		{
			manager.close(stmt);
			manager.releaseConnection(conn);
		}
	}
}
这样,一个模板类就完成了。我们也通过这个模板类将catch…finally…两段代码提出来了。我们来看看使用了这个模板类的数据层方法是怎么实现的:
new DataTemplate().execute(new DataManager()
{
	public void manageData()
	{
		String[] divisionData = null;
		conn = manager.getInstance().getConnection();
		stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
		stmt.setLong(1 ,productId.longValue() );
		stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
		stmt.execute();
		ResultSet rs = stmt.getCursor(2);
		int i = 0 ;
		String strDivision = "";
		while( rs.next() )
		{
			strDivision += rs.getString("DIVISION_ID") + "," ;
		}
		int length = strDivision.length() ;
		if(length != 0 )
		{
			strDivision = strDivision.substring(0,length - 1);
		}
		divisionData = StringUtil.split(strDivision, ",") ;
		map.put("Division", strDivision ) ;
		LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
	}
});
注意:本段代码仅供思路上的参考,没有经过上机测试。
我们可以看到,正是这个实现了DataManager接口得匿名内部类的使用,才使得我们解决了对try…catch…finally…语句的改造。这样,第一为我们解决了令人痛苦的重复代码;第二也让我们在数据层方法的编码中,直接关注对数据的操作,不用关心那些必需的但是与数据操作无关的东西。
我们现在来回想一下Spring框架的数据层,是不是正是使用了这种方法呢?
 
 
场景之三:一些多算法场合
假如我们有这样一个需求:我们的一个方法用来对数组排序并且依次打印各元素,对数组排序方法有很多种,用哪种方法排序交给用户自己确定。
对于这样一个需求,我们很容易解决。我们决定给哪些排序算法定义一个接口,具体的算法实现由用户自己完成,只要求他实现我们的接口就行。
public interface SortAlgor
{
        public void sort(int[] is);
}
这样,我们再在方法里实现先排序后打印,代码如下:
public void printSortedArray(int[] is,SortAlgor sa)
{
	……
	sa.sort(is);
	for(int i=0;i<is.length;i++)
	{
		System.out.print(is[i]+” “);
	}
	System.out.println();
}
客户端对上面方法的使用如下:
int[] is = new int[]{3,1,4,9,2};
printSortedArray(is,new SortAlgor()
{
	public void sort(is)
	{
		int k = 0;
		for(int i=0;i<is.length;i++)
		{
			for(int j=i+1;j<is.length;j++)
			{
				if(is[i]>is[j])
				{
					k = is[i];
					is[i] = is[j];
					is[j] = k;
				}
			}
		}
	}
});
这样的用法很多,我们都或多或少的被动的使用过。如在Swing编程中,我们经常需要对组件增加监听器对象,如下所示:
spinner2.addChangeListener(new ChangeListener()
{
	public void stateChanged(ChangeEvent e)
	{
		System.out.println("Source: " + e.getSource());
	}
}
		);
在Arrays包里,对元素为对象的数组的排序:
Arrays.sort(emps,new Comparator(){
	Public int compare(Object o1,Object o2)
	{
		return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();
	}
});
这样的例子还有很多,JDK教会了我们很多使用内部类的方法。随时我们都可以看一看API,看看还会在什么地方使用到内部类呢?
 
 
 
场景之四:适当使用内部类,使得代码更加灵活和富有扩展性
适当的使用内部类,可以使得你的代码更加灵活和富有扩展性。当然,在这里头起作用的还是一些模式的运行,但如果不配以内部类的使用,这些方法的使用效果就差远了。不信?请看下面的例子:
我们记得简单工厂模式的作用就是将客户对各个对象的依赖转移到了工厂类里。很显然,简单工厂模式并没有消除那些依赖,只是简单的将它们转移到了工厂类里。如果有新的对象增加进来,则我们需要修改工厂类。所以我们需要对工厂类做进一步的改造,进一步消除它对具体类的依赖。以前我们提供过一个使用反射来消除依赖的方法;这里,我们将提供另外一种方法。
这种方法是将工厂进一步抽象,而将具体的工厂类交由具体类的创建者来实现,这样,工厂类和具体类的依赖的问题就得到了解决。而工厂的使用者则调用抽象的工厂来获得具体类的对象。如下。
我们以一个生产形体的工厂为例,下面是这些形体的接口:
package polyFactory;
 
public interface Shape {
public void draw();
public void erase();
 
}
通过上面的描述,大家都可能已经猜到,这个抽象的工厂肯定使用的是模板方法模式。如下:
package polyFactory;

import java.util.HashMap;
import java.util.Map;


public abstract class ShapeFactory {
	protected abstract Shape create();
	private static Map factories = new HashMap();
	public static void addFactory(String id,ShapeFactory f)
	{
		factories.put(id,f);
	}
	public static final Shape createShape(String id)
	{
		if(!factories.containsKey(id))
		{
			try
			{
				Class.forName("polyFactory."+id);
			}
			catch(ClassNotFoundException e)
			{
				throw new RuntimeException("Bad shape creation : "+id);
			}
		}
		return ((ShapeFactory)factories.get(id)).create();
	}
}
不错,正是模板方法模式的运用。这个类蛮简单的:首先是一个create()方法,用来产生具体类的对象,留交各具体工厂实现去实现。然后是一个Map类型的静态变量,用来存放具体工厂的实现以及他们的ID号。接着的一个方法使用来增加一个具体工厂的实现。最后一个静态方法是用来获取具体对象,里面的那个Class.forName……的作用是调用以ID号为类名的类的一些静态的东西。
下面,我们来看具体的类的实现:
package polyFactory;
 
public class Circle implements Shape {
 
 
public void draw() {
        // TODO Auto-generated method stub
       System.out.println("the circle is drawing...");
}
 
 
public void erase() {
        // TODO Auto-generated method stub
       System.out.println("the circle is erasing...");
}
private static class Factory extends ShapeFactory
{
       protected Shape create()
        {
               return new Circle();
        }
}
static {ShapeFactory.addFactory("Circle",new Factory());}
 
}
这个类的其他的地方也平常得很。但就是后面的那个内部类Factory用得好。第一呢,这个类只做一件事,就是产生一个Circle对象,与其他类无关,就这一个条也就满足了使用内部类的条件。第二呢,这个Factory类需要是静态的,这也得要求它被使用内部类,不然,下面的ShapeFacotry.addFactory就没办法add了。而最后的那个静态的语句块是用来将具体的工厂类添加到抽象的工厂里面去。在抽象工厂里调用Class.forName就会执行这个静态的语句块了。
下面仍然是一个具体类:
package polyFactory;
 
 
public class Square implements Shape {
 
public void draw() {
        // TODO Auto-generated method stub
       System.out.println("the square is drawing...");
}
 
public void erase() {
        // TODO Auto-generated method stub
       System.out.println("the square is erasing...");
}
private static class Factory extends ShapeFactory
{
       protected Shape create()
        {
               return new Square();
        }
}
static {ShapeFactory.addFactory("Square",new Factory());}
 
}
最后,我们来测试一下:
String[] ids = new String[]{"Circle","Square","Square","Circle"};
        for(int i=0;i<ids.length;i++)
        {
               Shape shape = ShapeFactory.createShape(ids[i]);
               shape.draw();
               shape.erase();
        }
测试结果为:
the circle is drawing...
the circle is erasing...
the square is drawing...
the square is erasing...
the square is drawing...
the square is erasing...
the circle is drawing...
the circle is erasing...
       这个方法是巧妙地使用了内部类,将具体类的实现和它的具体工厂类绑定起来,由具体类的实现者在这个内部类的具体工厂里去产生一个具体类的对象,这当然容易得多。虽然需要每一个具体类都创建一个具体工厂类,但由于具体工厂类是一个内部类,这样也不会随着具体类的增加而不断增加新的工厂类,使得代码看起来很臃肿,这也是本方法不得不使用内部类的一个原因吧。

【Java基础知识 37】Java内部类、java内部类的作用 Java内部类是定义在另一个类内部的类,可以访问外部类的成员变量和方法。内部类可以分为成员内部类、局部内部类、匿名内部类和静态内部类四种类型。其中,成员内部类和局部内部类必须依托于外部类的实例存在,而静态内部类则可以独立存在。匿名内部类是一种没有名字的内部类,通常用于创建实现某个接口或继承某个类的对象。 阅读详情

相关推荐

Java基础:内部类

距今为止,我们了解的都是普通类的定义,那就是直接在IDEA或eclipse中直接新建一个class。新建完成后,你就会拥有一个class文件的定义,这种操作太简单了,时间长了就会枯燥,我们年轻人多需要更新潮和骚气的写法,好吧,既然你提到了那就使用内部类可以将一个类的定义放在另一个类的内部,这就是内部类。Java内部类‌是一种嵌套在另一个类(称为外部类)内部的类定义。它们可以访问外部类的所有成员(包括私有成员),同时也可以拥有自己的成员变量方法构造器以及嵌套类。

在技术的广袤天地里,本博客如精准罗盘。剖析前沿科技,深掘代码奥秘,以精炼笔触,带您穿越复杂技术迷宫,速达知识彼岸。 1118

Java的4种内部类的使用方式及适用场景

Java中有四种形式的内部类,在开发的过程中需要理清楚何时使用合适的内部类,内部类用好了可以提高编码效率、更好的实现封装、甚至可以巧妙实现多继承。当然,某些内部类用多了会削弱面向对象的设计思想,所以内部类不可滥用,要清楚各种形式内部类的作用和适用场景。

一只猿的自我修养 4130

浅谈Java内部类的四个应用场景

Java内部类是Java言语的一个很重要的概念,《Java编程思想》花了很大的篇幅来讲述这个概念。但是我们在实践中很少用到它,虽然我们在很多时候会被动的使用到它,但它仍然像一个幕后英雄一样,不为我们所知,不为我们所用。 本文不试图来讲述Java内部类的今生前世、来龙去脉,这些在网络上都已经汗牛充栋。如果读者想了解这些,可以在网络上搜索来学习。Java内部类总是躲在它的外部类里,像一个幕后英雄一样。但是幕后英雄也有用武之地,在很多时候,恰当的使用Java内部类能起到让人拍案叫绝的作用。本文试图谈一谈让这个幕后英雄也有用武之地的四个场景,希望引起大家对使用Java内部类的兴趣。

Java内部类以及使用场景

所谓内部类,即定义在另一个类中的类。那么,为什么会有内部类这个概念,他的使用场景又是什么呢?首先,来看一下内部类的特点: 1.它体现了一种代码的隐藏机制和访问控制机制,内部类与所在外部类有一定的关系,往往只有该外部类调用此内部类,所以没有必要专门用一个Java文件存放这个类。 public class Outer {   private int num;   privat...

dimigua4451的博客 718

电子发票二维码背后的秘密:10分钟看懂校验码、加密字符含义与防伪设计

本文深入解析电子发票二维码的结构与防伪设计,揭示校验码和加密字符的生成原理及验证方法。通过实际案例和技术细节,帮助财务人员理解电子发票的安全机制,提升防伪识别能力,确保税务合规。

weixin_29248611的博客 530

从FrSky到TBS:深度解析航模2.4G遥控协议江湖史(附ELRS高频头改装指南)

本文深度解析了航模2.4G遥控协议的技术演进史,从FrSky ACCST的兴衰到TBS Crossfire的崛起,再到开源协议ExpressLRS的革命性突破。文章不仅对比了各协议在延迟、距离与抗干扰能力上的技术内核,还提供了为多协议遥控器加装TBS Crossfire高频头的实战改装指南,帮助玩家打通协议壁垒,提升飞行体验。

weixin_29193259的博客 736

幕后英雄的用武之地——浅谈Java内部类的四个应用场景

                                                                    幕后英雄的用武之地                                                        ——浅谈Java内部类的四个应用场景 Java内部类是Java言语的一个很重要的概念,《Java编程思想》花了很大的篇幅来

软件的信雅达 2万+

Jupyter Notebook 命名出现“error”且运行后没反应

Jupyter Notebook 命名出现“error”且运行后没反应提前声明错误截图(方便大家看看是不是自己的错误)解决方法 提前声明 我的问题是在看到答主 @开始King的回答后才解决的,因为答主大大的文章后面有些地方不是很详细,我在这里再在King大大的基础上完善一下子 错误截图(方便大家看看是不是自己的错误) 1.命名失败,上面出现一个“error”字样 2.运行失败,无论是点击上方的运行按钮还是按快捷键shift+enter 都只会向下再增加一个代码块,而不会运行程序。 (也不是很多人出现的[*

qq_52770743的博客 1万+

Java基础(八)内部类

前言 嘿,java学习者,问你两个问题:如果提到线程你会不会立马想到接口和继承?如果提到接口和继承你会不会立马想到匿名内部类? 目录1. 内部类1.1 何为内部类?1.2 内部类的优缺点1.3 内部类的相关说明1.4 在方法中定义内部类1.5 static定义内部类2.匿名内部类案例何为匿名内部类?为什么要使用匿名内部类?匿名内部类的使用匿名方法在多线程上的实现3、Lambda表达式Lambda表...

Raindropcds的博客 271

MSDN Win10镜像缺少驱动?这里有全面解决方案

针对MSDN Win10镜像缺少驱动的问题,本文提供了四种解决方案:厂商官网下载驱动程序、利用Windows更新获取驱动、使用第三方驱动更新工具以及使用集成驱动的Win10系统镜像。每种方案都有其优缺点,用户可以根据自己的需求和实际情况选择合适的方案。建议优先考虑官方渠道:官方渠道下载的驱动程序稳定可靠,是解决问题的首选方案。谨慎选择第三方工具:使用第三方工具时,务必选择信誉好、无广告捆绑的工具,并注意保护个人隐私和计算机安全。备份重要数据:在进行系统安装或更新前,务必备份重要数据以防丢失。

nntxthml的博客 1523

1.1.4 运用防火墙实现入侵防御

摘要:本文详细介绍了某公司网络拓扑中防火墙FW1的配置过程。主要内容包括:1)通过web界面登录防火墙;2)配置三个接口的IP地址及所属安全区域;3)创建两个入侵防御配置文件(anti_untrust和anti_trust);4)配置安全策略untrust2dmz和trust2dmz,分别允许公网/内网访问WWW服务器;5)保存配置。操作步骤配有详细截图说明,涉及接口配置、安全区域划分、入侵防御策略设定等关键环节,最终实现内外网对服务器Server1的安全访问控制。(149字)

Ljs040411的博客 2134

Java程序基础⑧抽象类+Object类+内部类

Java程序基础⑧抽象类+Object类+内部类(抽象类概念+语法+特性+作用+Object类+toString方法+equals方法+hashcode方法+静态内部类+实例化内部类+匿名内部类+局部内部类)

参考书籍:《C语言程序设计》《数据结构》《C++ Primer》《Effective C++》《STL源码剖析》《现代操作系统》《UNIX环境高级编程》《图解TCP/IP》《图解HTTP》《Linux高性能服务器编程》《剑指Offer》《算法导论》 1128

EDK2多平台编译实战:从树莓派到RK3399的UEFI固件构建

本文提供了从树莓派到RK3399的EDK2多平台编译实战指南。详细介绍了UEFI固件构建的环境搭建、交叉编译配置、平台描述文件修改及常见问题排查,帮助开发者掌握为不同ARM架构硬件构建标准化启动固件的核心技能。

weixin_29193259的博客 836

java基础八-内部类详解

1、内部类说明(1)内部类可以访问外部类的成员(变量、方法);但是外部类不能访问内部类的成员(2)普通内部类可以访问外部类的静态成员和非静态成员;但是静态内部类只能访问外部类的静态成员(3)普通内部类不能定义静态成员,除非用final修饰;静态内部类可以定义静态成员和非静态成员2、成员内部类的定义classOuter{privateString name;privatest...

qq_35930102的博客 139

整理 钢琴 约翰·汤普森现代钢琴(大汤)

大汤

TS的博客 3999

SAP_MM模块采购订单显示含税价&不含税简介

不含税价(Net Price):基础商品价格,不包含税金。含税价(Gross Price):基础价格加上适用税金后的总价。在SAP中,采购订单通常以不含税价为基础,通过配置税码和定价方案,系统会自动计算含税总价。

我小时候很黑的博客 2303

Java 基础学习(八)多态、接口、造型与内部类

2.1.1 多继承问题讨论接口之前,先看一个物品归类的生活实例:查看这个商品分类,可看出:1、相同类别的商品具有相似特征,且属性类似:比如“新鲜水果“类、”海鲜水产“类2、同类标签便于管理统一存储和调度3、也存在跨类别的分类标签:比如“地方特产“、”国际美食“4、跨类别的分类标签体现了一个物品属于多种类型的现象,这种现象称为“多继承”如果用 Java 代码来表现上述情况,会发现,Java的继承可以实现树形分类,但是无法处理跨类别标签:不过,Java提供了接口,解决了跨类型的继承问题。

2301_79227925的博客 1192

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java 基础开发Word总结《 八》内部类和异常

1内部类 1.1内部类的概述 将类定义在另一个类的内部则成为内部类。其实就是类定义的位置发生了变化。 在一个类中,定义在类中的叫成员变量,定义在函数中的叫成员函数,那么根据类定义的位置也可以分为成员内部类和局部内部类。 备注:内部类生产的class文件为 “外部类$内部类”,为了标明该内部类是属于具体哪个外部类的。 1.2成员内部类的访问方式 1.内部类可以直接访问外部类的成员属性。(孙

chenfengbao的博客 511

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java基础(八) Java修饰符及接口详解之(二) 内部类

Java基础(八) Java修饰符及接口详解之(二) 内部类 总体来熟,Java内部类为了从维护性的考虑,使用的并不是特别多。但是在某些情况下,类仅仅被使用一次,通常使用的就是匿名内部类。内部类 8. 内部类在一个类的内部定义的类称为内部类。内部类分为:成员内部类 静态内部类 局部内部类 匿名内部类。顶层类(正常类)只能处于public和默认访问级别,而成员内部类可以处于public, prot

Be yourself. 916

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

JAVA基础再回首(八)——多态、(成员、局部、匿名)内部类

JAVA基础再回首(八)——多态、(成员、局部、匿名)内部类 只有一条路不能选择——那就是放弃的路;只有一条路不能拒绝——那就是成长的路。

aduroidpc's Blog 2894

java接口 详解 二_Java基础(八) Java修饰符及接口详解之(二) 内部类

Java基础(八) Java修饰符及接口详解之(二) 内部类总体来熟,Java内部类为了从维护性的考虑,使用的并不是特别多。但是在某些情况下,类仅仅被使用一次,通常使用的就是匿名内部类。内部类8. 内部类在一个类的内部定义的类称为内部类。内部类分为:成员内部类 静态内部类 局部内部类 匿名内部类。顶层类(正常类)只能处于public和默认访问级别,而成员内部类可以处于public, protect...

weixin_39528559的博客 101

Java基础------知识点整理(八)-----内部类

1.内部类:将一个类定义到另一个类里面,对立面的类叫内部类(嵌套类,内置类等) 2.内部类特点 (1)内部类可以访问外部类中的成员(内部类相当于外部类的一个成员,所以可以直接访问,尤其是private变量),如果不用内部类访问private成员还得先创建一个对象,然后             通过set,get方法才能访问private成员,所以此时为了方便创建内部类 (2)外部类要

kwang0131的博客 410

【Java|基础篇】内部类

内部类就是在一个类中再定义一个类,内部类也是封装的体现.它可以被声明为public、protected、private 或默认访问控制符。内部类可以访问外部类的所有成员变量和方法,包括私有成员。内部类可以用来实现一些特殊的功能,比如实现回调函数、事件处理等。常见的内部类包括实例内部类(成员内部类)、静态内部类、本地内部类、匿名内部类等。内部类在Java中的一个重要特性,要重点掌握实例内部类,静态内部类和匿名内部类.希望这篇文章能帮到你!专栏:《从零开始的Java学习之旅》在不断更新中,欢迎订阅!

云泽野の编程日记 1万+

【Java基础】匿名内部类

详细讲解Java的匿名内部类的定义,使用方法,使用例子

小吉妙妙屋 1万+

Java基础——内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。可以把内部类理解成寄生,外部类理解成宿主。匿名内部类:是内部类的简化写法。他是一个隐含了名字的内部类。开发中,最常用到的内部类就是匿名内部类了。

允诺@晴天的博客 3209

Java基础:内部类详解

1、首先,把内部类作为外部类的一个特殊的成员来看待,因此它有类成员的封闭等级:private,protected,default,public,它有类成员的修饰符: static,final,abstract;2、非静态内部类nested inner class:隐含有一个外部类的指针this,因此,它可以访问外部类的一切资源,包括private。外部类访问内部类的成员,先要取得内部类的对象,并且取决于内部类成员的封装等级。非静态内部类不能包含任何static成员。

愿你我都能实现自己的梦想 1158
上一篇: Java面试题集(71-85)
下一篇: java8内存模型——永久代和元空间
冷静BB
博客等级 码龄12年 298粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值