声明:本博客为原创博客。未经同意,不得转载。原文链接为 http://blog.csdn.net/bettarwang/article/details/27012421

      我们都知道。非静态内部类能够訪问外部类的私有成员(包含私有变量和方法),这也正是使用非静态内部类与普通类的一个重要差别:非静态内部类是依赖于外部类对象而存在的,这样的依赖就包含它要能自由地訪问外部类对象的全部成员(由于private成员都能够訪问了,其它权限的成员更不在话下。只是一般来说一个内部类仅仅会訪问外部类的部分成员而不是全部)。比方心脏作为单独的一个类存在可能没有太大的意义,它必须依附于详细的Person对象存在才有意义。并且心脏它要能够自由地訪问Person对象的一些成员,如血液、营养等。

       显然,外部类对于非静态内部类而言是全然透明的。可是实际上,外部类与非静态内部类的还有一个特征尽管不经常使用。却也值得注意,那就是非静态内部类事实上跟外部类的其它成员相似。仅仅是它的一个成员而已,因而即使非静态内部类的修饰符为private、即使非静态内部类的构造器修饰符为private,外部类也能够新建非静态内部类的对象。例如以下例所看到的:

import java.util.*;

class Car
{
private float gasAmount;
private String gasType;
public Car(float gasAmount,String gasType)
{
this.gasAmount=gasAmount;
this.gasType=gasType;
new Engine();
} private void print(String msg)
{
System.out.println(msg);
}
private class Engine
{
private int rotateSpeed;
private Engine()
{
if(gasType=="93#"&&gasAmount>0)
{
rotateSpeed=1500;
print("Gas amount is "+String.valueOf(gasAmount)+" gallon now.Engine starts successfully");
}
else if(gasType=="93#"&&gasAmount<=0)
{
rotateSpeed=0;
print("Engine starts failed! Please add fuel first!");
}
else
{
rotateSpeed=0;
print("Gas type is not correct!");
} }
}
} public class OuterSample
{
public static void main(String[]args)
{
new Car(2.0f,"93#");
new Car(0.0f,"93#");
}
}

输出结果例如以下图所看到的:

显然,由输出结果可看出:第一。尽管非静态内部类的修饰符和构造器均为private,可是外部类仍然能够创建内部类对象。第二,非静态内部类能够使用外部类的private成员(如此处的private成员变量gasType及gasAmount); 

       还有一个经常被人忽略的地方是:在外部类的方法中,也能够通过创建非静态内部类的对象来訪问内部类包含private成员在内的全部成员,只是注意必须是外部类的实例成员才行,而不能在外部类的静态成员(包含静态方法和静态初始化块)中使用非静态内部类。原因非常easy:非静态内部类可看作是外部类的一个实例成员。而静态成员不能訪问实例成员。

例如以下例所看到的:

import java.util.*;

class Car
{
private float gasAmount;
private String gasType;
private Engine engine;
public Car(float gasAmount,String gasType)
{
this.gasAmount=gasAmount;
this.gasType=gasType;
engine=new Engine();
} public void printRotateSpeed()
{
//事实上写成print("Rotate speed is "+String.valueOf(new Engine().rotateSpeed));也行。可是不太符合实际。由于一车相应一引擎
print("Rotate speed is "+String.valueOf(engine.rotateSpeed));
}
private void print(String msg)
{
System.out.println(msg);
}
private class Engine
{
private int rotateSpeed;
private Engine()
{
if(gasType=="93#"&&gasAmount>0)
{
rotateSpeed=1500;
print("Gas amount is "+String.valueOf(gasAmount)+" gallon now.Engine starts successfully");
}
else if(gasType=="93#"&&gasAmount<=0)
{
rotateSpeed=0;
print("Engine starts failed! Please add fuel first!");
}
else
{
rotateSpeed=0;
print("Gas type is not correct!");
} }
}
} public class OuterSample
{
public static void main(String[]args)
{
Car car01=new Car(2.0f,"93#");
car01.printRotateSpeed();
Car car02=new Car(0.0f,"93#");
car02.printRotateSpeed();
}
}

输出结果例如以下图:


       从输出结果能够看出,在外部类的方法printRotateSpeed()中。通过非静态内部类的对象来a訪问了其private成员rotateSpeed,这事实上跟实际中的情况非常像,即发动机从汽车处获得燃料信息,汽车再从发动机处获得转速并显示在仪表盘上。

      综上,非静态内部类可自由訪问外部类包含privated成员在内的全部成员,外部类也可通过创建内部类的对象来訪问其包含private成员在内的全部成员。所以它们尽管在类层面不是相互可见的,可是从广义上来说具有相互可见性,这也是我在题目上打上双引號的原因。

Java中内部类揭秘(一):外部类与非静态内部类的”相互可见性“的更多相关文章

  1. java——多线程——内部类共享同一个外部类对象的成员变量

    public class Shop { public static void main(String[] args) { Outer o=new Outer(); Thread t1=o.getSal ...

  2. 深入理解Java中为什么内部类可以访问外部类的成员

    内部类简介 虽然Java是一门相对比较简单的编程语言,但是对于初学者, 还是有很多东西感觉云里雾里, 理解的不是很清晰.内部类就是一个经常让初学者感到迷惑的特性. 即使现在我自认为Java学的不错了, ...

  3. 牛客网Java刷题知识点之什么是内部类、为什么要使用内部类、内部类如何使用外部类的属性和方法、成员内部类、局部内部类、静态内部类、匿名内部类

    不多说,直接上干货! 可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 内部类 ...

  4. “全栈2019”Java第八十章:外部类是否能实现本类中的接口?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. java中内部类使用小结

    内部类是指在一个外部类中再定义一个类,类名不需要和文件名相同 内部类可以是静态的,类的修饰符可以是private,default,protect,public修饰 ,而外部类只能是public 和 d ...

  6. java中内部类的积累

    放在一个类的内部的类我们就叫内部类. 二. 作用 1.内部类可以很好的实现隐藏 一般的非内部类,是不允许有 private 与protected权限的,但内部类可以 2.内部类拥有外围类的所有元素的访 ...

  7. java中内部类的讲解

    java中有一个内部类的概念,由于之前一直比较忙,没有单独拿出时间总结一下,今天我就把内部类的相关知识进行一下汇总,如果有不足之处,欢迎批评指正. 1)java内部类的概念.       在一个类的的 ...

  8. Java中内部类的骚操作

      10.1 如何定义内部类 如代码10.1-1 所示 public class Parcel1 { public class Contents{ private int value = 0;​ pu ...

  9. java中内部类

    package com.xt.instanceoftest; import com.xt.instanceoftest.Body.Heart; public class StaticInnerClas ...

随机推荐

  1. MyEclipse安装EGit插件方法

    摘要: 先了解自己的MyEclipse是基于哪个版本的Eclipse优化的,然后到EGit网站找对应的EGit版本,下载压缩包,解压安装. 在网上看到有人说并不是任意版本的EGit插件都能适配你的My ...

  2. Oracle:create pfile from spfile:rac下要小心该操作啊!

    默认在原位置创建一个pfile的ora初始化参数文件!! 这在rac下会带来问题,因为rac下,当使用asm存储时,instance的启动参数文件就是pfile(其内容是指向一个spfile).如果不 ...

  3. linux下 安装mysql教程

    安装环境:系统是 centos6.5 1.下载 下载地址:http://dev.mysql.com/downloads/mysql/5.6.html#downloads 下载版本:我这里选择的5.6. ...

  4. 从源代码来理解ArrayList和LinkedList差别

    从源代码理解ArrayList和LinkedList差别 ArrayList ArrayList默认容量为10,实质是一个数组用于存放元素,size表示ArrayList所包括的元素个数. Array ...

  5. Python 流程控制:while

    while 语法如下,当条件为假时循环才退出,否则会一直循环下去: while 条件: 执行语句 当条件为假时,才会执行else语句: while 条件: 执行语句 else: 执行语句

  6. Python urllib2 模块

    urllib2.urlopen(url, data=None, timeout=<object object>) :用于打开一个URL,URL可以是一个字符串也可以是一个请求对象,data ...

  7. js禁止img拖动

    其实只需要一句代码即可,那就是阻止元素的默认事件: <body> <img src="./../imgs/cat.jpg" id="test" ...

  8. golang 小知识-持续更新中

    Golang 中的指针 - Pointer Go 的原生数据类型可以分为基本类型和高级类型,基本类型主要包含 string, bool, int 及 float 系列,高级类型包含 struct,ar ...

  9. xdebug和最重要的php调试技巧

    好几年没有写PHP代码了,最近写了一些.我比较厌烦php,主要是调试麻烦,要按无数次F5,经常刷出空白. 以前调试总是依赖于在代码中加入下面两行 error_reporting(E_ALL ^ E_N ...

  10. log4j和commons- logging(好文整理转载)

    一 :为什么同时使用commons-logging和Log4j?为什么不仅使用其中之一? Commons-loggin的目的是为 “所有的Java日志实现”提供一个统一的接口,它自身的日志功能平常弱( ...