实例内部类静态内部类局部内部类主要特征内部类的实例引用特定的外部类的实例内部类的实例不与外部类的任何实例关联可见范围是所在的方法可用的修饰符访问控制修饰符,abstract,final访问控制修饰符,static,abstract,finalabstract,final可以访问外部类的哪些成员可以直接访问外部类的所有成员只能直接访问外部类的静态成员可以直接访问外部类的所有成员,并且能访问所在方法的final类型的变量和参数拥有成员类型只能拥有实例成员可以拥有静态成员和实例成员只能拥有实例成员外部类如何访问内部类的成员必须通过内部类的实例来访问对于静态成员,可以通过内部类的完整类名来访问必须通过内部类的实例来访问
在其他类中创建内部类的对象时,必须要使用外部类的实例来创建。比如类B是类A的内部类,则语句AB=new AB()将是错误的。正确的方法是先创建一个类A的对象,比如A ma=new ma();然后再用这个对象来创建内部类的实例,比如AB mab=manew B();这里要注意后面的语法manew B()。也可以把这两步合为一步,比如AB mab=new A()new B();注意,这里使用了两个new运算符,如果只有一个将是错误的,比如AB mab=new A()B();是错误的,new A()B()语句JAVA会理解为创建一个无名的引用,然后由这个引用调用类A中的B()函数。如果需要调用的构造函数不是默认的,则可以这样创建比如AB mab=new A(2)new B();或者分为两步A ma=new A(2); AB mab=manew B();
而且我也怕是不是会重新建个棋盘,那就不行了!
这个你可以放心,不会创建两个棋盘,下面举例验证
public class A2 extends JFrame {
public static void main(String[] args) {
A ma=new A(); //可以看到在这里并没有创建内部类,也就是说内部类中的bbb并没有输出
AA1 ma1=manew A1(); //调用内部类的方法,当然内部类如果有带参数构造函数,则还应在内部类中加上参数。
ma1f();
}}
class A{
A(){Systemoutprintln("aaa");}
class A1{
A1(){Systemoutprintln("bbb");}
public void f(){Systemoutprintln("kkk");}}
}
在Java的单例模式里面,很多人都知道懒汉式要比饿汉式更优雅,这里我想告诉你的是,我这里,有一种更优雅的单例设计模式。
1、什么是类级内部类? 简单点说,类级内部类指的是,有static修饰的成员内部类。如果没有static修饰的成员式内 部类被称为对象级内部类。
2、类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此 可以直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。
3、类级内部类中,可以定义静态的方法。在静态方法中只能引用外部类中的静态成员方法或变量。
4、类级内部类相当于其外部类的成员,只有在第一次被使用的时候才会被装载。
大家都知道,在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制, 但是在某些情况下,JVM已经隐含的为您执行了同步,这些情况下就不用自己再来进行同步控制了。
1、由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
2、访问final字段时
3、在创建线程之前创建对象时
4、线程可以看见它将要处理的对象时
要想很简单的实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的 安全性。比如前面的饿汉式实现方式。但是这样一来,不是会浪费一定的空间吗?因为这种 实现方式,会在类装载的时候就初始化对象,不管你需不需要。 如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要不使用到这个类级内部类, 那就不会创建对象实例,从而同步实现延迟加载和线程安全。
要么把关键字去掉static去掉;
要么在内部类前面加个static关键字
private static class Saler{
Saler(){
}
}
Java语言允许在类中再定义类,这种在其它类内部定义的类就叫内部类。内部类又分为:常规内部类、局部内部类、匿名内部类和静态嵌套类四种。
1、静态内部类定义
静态内部类,定义在类中,任何方法外,用static定义;静态内部类只能访问外部类的静态成员。
生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成:OuterInner in=new OuterInner();而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。可以定义私有静态内部类。
2、java实现静态内部类注意事项
将某个内部类定义为静态类,跟将其他类定义为静态类的方法基本相同,引用规则也基本一致。不过其细节方面仍然有很大的不同。具体来说,主要有如下几个地方要引起注意。
1)一般情况下,如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态成员变量与静态成员方法的。也就是说,在非静态内部类中不可以声明静态成员
2)一般非静态外部类可以随意访问其外部类的成员变量以及方法(包括声明为private的方法),但是如果一个内部类被声明为static,则其在访问包括自身的外部类会有诸多的限制。静态内部类不能访问其外部类的非静态成员变量和方法
3)在一个类中创建非静态成员内部类的时候,有一个强制性的规定,即内部类的实例一定要绑定在外部类的实例中。然后要在一个外部类中定义一个静态的内部类,不需要利用关键字new来创建内部类的实例。即在创建静态类内部对象时,不需要其外部类的对象
3、静态内部类示例
java在实现LinkedList时使用了如下内部类:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, javaioSerializable
{
private static class Entry<E> {
E element;
Entry<E> next;
Entry<E> previous;
Entry(E element, Entry<E> next, Entry<E> previous) {
thiselement = element;
thisnext = next;
thisprevious = previous;
}
}
private Entry<E> addBefore(E e, Entry<E> entry) {
Entry<E> newEntry = new Entry<E>(e, entry, entryprevious);
newEntrypreviousnext = newEntry;
newEntrynextprevious = newEntry;
size++;
modCount++;
return newEntry;
}
}
这里即静态内部类的典型用法
//执行了new Q();调用的是Q类的无参构造器,因此q变量对应的是Q类的实例对象。
Q q=new Q();
//变量q对应是Q类的实例对象,由于Q类继承了Q2类,也实现了Q1接口,因此q也属于Q2类型和Q1类型,换句话就是q可以调用Q2和Q1的非私有方法,首先Q类中没有b()方法, Q1中也没有定义b()方法,所以这里就只可能是调用Q2中定义的b()方法了,而b方法中返回的是一个Q3实例对象,而且执行的语句是new Q3("访问内部类中的b()方法"); 调用的是Q3的有参构造器,字符串"访问内部类中的b()方法"作为参数s,并在调用Q3的有参构造器时调用了输出语句,输出的就是"访问内部类中的b()方法",而且q1实际上是Q3的实例对象,所以q1可以调用Q3的方法。
Q1 q1=qb();
//由于Q3实现了Q1接口,因此必须实现Q1中的接口方法a(), 对应的实现就是Q3中的a()方法,所以此处调用的实际上是Q3中的a()方法, 输出语句"访问内部类中的a()方法"
q1a();
//由于q对应的是Q类的实例对象, 而且Q类内部也实现了Q1接口中定义的a()方法, 那么这里很显然调用的是Q类中的a()方法了, 输出语句"访问外部类中的a()方法"。
qa();
总结:
书本大概意思是使用私有内部类有时候可以给一些方法的实现带来便利,因为有时候一些方法的实现比较复杂,调用者甚至可能不知道要用到什么参数,或者根本不知道该调用哪个对象的方法,那么就可以考虑把这些方法放到私有内部类中,调用对应方法时不需要调用者考虑应该创建哪些实例对象,或者该方法是如何实现等问题,这些工作都是内部自动完成,调用者只需要调用对外开放的方法即可。就比如这里的例子,要想调用Q3中的a()方法就必须调用Q3的构造器,那么就需要传入参数s,而实际上我们调用时根本不用担心参数是什么,或者怎么传。
使用匿名内部类课使代码更加简洁、紧凑,模块化程度更高。内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到。然而这个不是我说的重点,我说的很简单,就是匿名内部类的两种实现方式:第一种,继承一个类,重写其方法;第二种,实现一个接口(可以是多个),实现其方法。
public class TestAnonymousInterClass{
public static void main(String args[]){
TestAnonymousInterClass test=new TestAnonymousInterClass();
testshow();
}
//在这个方法中构造了一个匿名内部类
private void show(){
Out anonyInter=new Out(){// 获取匿名内部类实例
void show(){//重写父类的方法
Systemoutprintln("this is Anonymous InterClass showing");
}
};
anonyIntershow();// 调用其方法
}
}
// 这是一个已经存在的类,匿名内部类通过重写其方法,将会获得另外的实现
class Out{
void show(){
Systemoutprintln("this is Out showing");
}
}
程序运行的输出结果为:
this is Anonymous InterClass showing
所以在这里看出,匿名内部类有了自己的实现。其实很简单,使用匿名内部类是因为我这地方需要有点什么特殊的实现,所以我就在这地方把具体实现也给了出来了。然后我就在这地方获取它的实例,调用它的方法。
接口的方式,只要把父类换成接口就行了,没必要给出代码了。
使用匿名内部类时我们不要忘了我们的目的,我们只是在这地方想对某个类有特殊的实现。而不要想得太多,在匿名内部编写其它的方法。在匿名内部类中编写的自己的方法是不可见的。此种做法是毫无意义的,当然一般也不会这么做。在这里只是告诉初学者对于匿名内部类不要想的太多,而要这么想:匿名内部类就是重写父类或接口的方法。
匿名内部类是没有名字的,所以我们没办法获得其类型,而只能把它当作超类或接口类型来使用。
一般来说,外部类调用内部类的方法分为以下几种情况:
1使用static可以声明一个内部类, 可以直接在外部调用
// 定义外部类
class Outer
{
// 定义外部类的私有属性
private static String info = "hello world";
// 使用static定义内部类为外部类
static class Inner
{
// 定义内部类的方法
public void print()
{
// 直接访问外部类的私有属性
Systemoutprintln(info);
}
};
// 定义外部类的方法
public void fun()
{
// 通过内部类的实例化对象调用方法
new Inner()print();
}
};
public class InnerClassDemo03
{
public static void main(String args[])
{
// 调用外部类的fun()方法
new OuterInner()print() ;
}
};
2不使用statc声明一个内部类 ,使外部调用
//定义外部类
class Outer
{
//定义外部类的私有属性
private String info = "hello world";
//定义内部类
class Inner
{
//定义内部类的方法
public void print()
{
//直接访问外部类的私有属性
Systemoutprintln(info);
}
};
//定义外部类的方法
public void fun()
{
//通过内部类的实例化对象调用方法
new Inner()print();
}
};
public class InnerClassDemo04
{
public static void main(String args[])
{
//外部类实例化对象
Outer out = new Outer();
//实例化内部类对象
OuterInner in = outnew Inner();
//调用内部类的方法
inprint();
}
};
3在方法中定义内部类 ,使外部调用
//定义外部类
class Outer
{
//定义外部类的私有属性
private String info = "hello world";
//定义外部类的方法
public void fun(final int temp)
{
//在方法中定义的内部类
class Inner
{
//定义内部类的方法
public void print()
{
//直接访问外部类的私有属性
Systemoutprintln("类中的属性:" + info);
Systemoutprintln("方法中的参数:" + temp);
}
};
//通过内部类的实例化对象调用方法
new Inner()print();
}
};
public class InnerClassDemo05
{
public static void main(String args[]){
//调用外部类的方法
new Outer()fun(30);
}
};
以上就是关于如何理解“实例内部类的实例自动拥有外部类实例的引用”全部的内容,包括:如何理解“实例内部类的实例自动拥有外部类实例的引用”、Java如何调用内部类的方法、研磨设计模式之单例模式(内部类)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)