菜鸡的Java笔记 第二十六 - java 内部类
/* innerClass
从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的
讲解它的目的第一个是为了解释概念,另外一个就是也是为后期的一些复杂程序做铺垫
所谓的内部类指的是在一个类的内部(外部类)定义类结构的一种处理形式
*/
/* 内部类的基本概念
类的组成永远都是只有两点:成员(Field),方法(Method),但是几乎所有的程序里面斗不会对嵌套的结构有任何的限定
所以内部类指的是在一个类的内部可以继续嵌套其他类结构的一种形式代码
并且从理论上来讲可以一直嵌套下去
下面首先来看一下内部类的基本形式
范例:观察内部类代码
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
public void fun(){
lnner in = new lnner(): //实例化内部类对象
in.print(): // 调用内部类的方法
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
// 结果 Hello World!
类本身的核心组成就应该是属性和方法,但是如果引用了内部类,就相当于破坏了这样的程序结构
所以内部类所带来的最为严重的问题就在于程序结构的破坏,但是破坏了那么也应该有一些收益
那么内部类的好处在哪里呢?为了观察出内部类的好处,那么下面将内部类拿出来,变为两个类
范例:内部类拿出来
class Outer{ // 外部类
private String info = "Hello World!":
public void fun(){
// 将当前对象传递到内部类之中
lnner in = new lnner(this): //实例化内部类对象
in.print(): // 调用内部类的方法
}
// 为in定义一个getter方法
public String getlnfo(){
return info:
}
}
class lnner{ // 内部类
private Outer temp: // 此处应该接收外部类实例化好的Outer类对象
public lnner(Outer temp){
this.temp = temp:
}
public void print(){
// 此处需要访问外部类中的私有属性,所以不能够直接输出属性,需要Outer类提供有getter
// 方法应该由对象进行调用,所以现在需要有一个实例化对象
// 相当于就是外部的out。getlnfo()
System,out.println(this.temp.getlnfo()): // 输出info 属性内容
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
// 结果 Hello World!
代码修改完成之后实际上就可以感受到内部类的最大好处是可以直接进行外部类中私有属性的直接访问
那么清楚内部类的基本定义之后,实际上现在又会存在有一下几个问题:
1.在编写代码一直强调:只要是属性的访问,一定要加上“this ”,这个时候由于属性是外部类中的
所以要想操作this 那么就必须使用“外部类.this.属性” ( 上面: Outer.this.info)
如果内部类中的方法直接采用了“this.属于”表示的是什么,只是本类(内部类)中的属性
2.以上的代码发现内部类可以方便访问外部类中的私有属性,同时发现外部类中的fun()方法里面也占着内部类的对象
那么内部类的私有属性外部类也可以直接利用对象访问
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
private String msg = "+++++++++":// 内部类的私有属性
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
public void fun(){
lnner in = new lnner(): //实例化内部类对象
in.print(): // 调用内部类的方法
System.out.println(in.msg):// 内部类对象直接调用属性
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
/*
结果
Hello World!
++++++++++++
*/
内部类与外部类之间的私有属性都是可以直接进行访问的,这一点要比分为两个类更加的方便
3.现在发现实例化内部类的对象操作都是在外部类中的fun()方法里面完成的
那么如果现在不希望通过外部类的方法操作内部类,那么也可以根据一下的语法,直接在其他类实例化内部类对象
语法结构:
外部类名称.内部类名称 对象名称 = new 外部类().内部类()
内部类的标准的名称应该是“外部类.内部类”,只不过“.”不可能直接出现在文件中
所以java 将其进行了转换,在文件名称中使用“$”来代替“.”
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner in = new Outer().new lnner():
in.print():
}
}
// 结果 Hello World!
4.内部类中可以利用private定义私有内部类:
class Outer{ // 外部类
private String info = "Hello World!":
private class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner in = new Outer().new lnner():
in.print():
}
}
// 结果: 出错
对于内部类的概念与它的结构有个先期的认识即可
*/
/* 内部类定义深入
在之前使用的都是普通类的形式进行了内部类的定义,实际上在内部结构上也可以应用在抽象类和接口上
范例:在抽象类上定义内部类
abstract class AbstractOuter{ // 抽象类的外部类
public abstract void peintOuter();
abstract class AbstractInner{ // 抽象内部类
public abstract void printInner();
}
class Inner{ // 普通的内部类
public void print(){
System.out.println("加油!");
}
}
}
class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
public void peintOuter(){
new Inner().print(); // 实例化内部类的对象调用方法
}
}
public class innerClass{
public static void main(String args[]){
AbstractOuter out = new OuterImpl();
out.peintOuter();
}
}
在定义内部抽象类的时候是不会影响到子类的,也就是说子类只需要覆写它所继承的抽象类中的抽象方法即可
范例:定义内部抽象类的子类
abstract class AbstractOuter{ // 抽象类的外部类
public abstract void peintOuter();
abstract class AbstractInner{ // 抽象内部类
public abstract void printInner();
}
class Inner{ // 普通的内部类
public void print(){
System.out.println("加油!");
}
}
}
class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
public void peintOuter(){
new Inner().print(); // 实例化内部类的对象调用方法
}
class InnerImpl extends AbstractInner{ // 内部抽象类
public void printInner(){
new Inner().print();
}
}
}
public class innerClass{
public static void main(String args[]){
AbstractOuter.AbstractInner in = new OuterImpl(),new InnerImpl();
in.peintOuter();
}
}
除了内部抽象类之外也可以实现内部的接口定义
范例:定义内部接口
interface IOuter{
public void peintOuter();
interface IInner{
public void printInner();
}
class B{
public void print(){
System.out.println("++++++++");
}
}
}
class OuterImpl implements IOuter{
public void peintOuter(){
class InnerImpl implements IInner{
public void printInner(){
new B().print();
}
}
}
}
public class innerClass{
public static void main(String args[]){
IOuter.IInner in = new OuterImpl().new InnerImpl();
in.printInner();
}
}
内部类完整的打破了程序结构定义要求,也就是说程序里面没有对内部类的结构做出任何的限制,只要该定义符合语法要求即可使用
*/
/* 利用static定义内部类
利用static定义的属性或者是方法,是不受到类的控制的,也就是说相当于是一个局外的结构
所以如果内部类上用了static定义,那么就表示此内部类变为了一个外部类,但是需要注意的是,如果它使用了static定义,那么只能够访问外部类中的static属性
范例:利用static定义内部类
class Outer{ // 外部类
private static String info = "Hello World!":
static class lnner{ // 内部类
public void print(){
System.out.println(info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
}
}
那么既然现在static的内部类变为了外部类,外部类就可以被其他类直接进行操作
但是这个时候的实例化对象格式:
外部类名称.内部类名称 对象名称 = new 外部类.内部类():
加上了static之后,那么实际上也就表示这个内部类的名字就成了“外部类.内部类”
范例:实例化内部类对象
class Outer{ // 外部类
private static String info = "Hello World!":
static class lnner{ // 内部类
public void print(){
System.out.println(info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner oi = new Outer.lnner():
oi.print():
}
}
// 结果 Hello World!
以后见到程序类库中出现有“Xxxx.Xxxx”就表示内部类
对于 static 定义内部类的形式在实际开发之中使用很多,但是也可以在接口上使用,即:接口内部可以使用 static 定义外部接口
范例:
interface IOuter{
static interface IInner{ // 静态的内部接口
public void print();
}
}
class InnerImpl implements IOuter.IInner{
public void print(){
System.ou.println("+++++++++");
}
}
public class innerClass{
public static void main(String args[]){
IOuter.IInner oi = new InnerImpl():
oi.print():
}
}
*/
/* 方法中定义内部类
理论上内部类可以在任何的位置上定义,包括:代码块中,类中,方法中。所以在实际的开发之中,有可能直接在方法里使用内部类
范例:观察方法中定义内部类
class Outer{ // 外部类
private String info = "Hello World!":
public void dun(int temp){ // 方法中的参数
double sal = 9000.0: // 方法中定义的普通变量
class lnner{ // 内部类,方法中定义
public void print(){
System.out.println("Outer类中的info属性= "+Outer.this.info):
System.out.println("fun()方法中的参数,temp = "+temp):
System.out.println("fun()方法定义的临时变量,sal ="+sal):
}
}
new lnner().print():// 实例化内部类对象,调用方法输出
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():// 实例化Outer类对象
out.fun(100):
}
}
/*
结果
Outer类中的info属性= Hello World!
fun()方法中的参数,temp = 100
fun()方法定义的临时变量,sal = 9000.0
*/
注意:现在使用的是JDK1.8版本
那么这个版本的好处是避免了一些复杂的细节,之所以会避免是为了整体的设计考虑的,而以上的代码,在JDK1.7时就会出现问题
因为在JDK1.7以前有一个约定,如果一个方法中定义了内部类,那么这个内部类要想访问方法的参数或者是定义的变量,则参数或者是变量前必须加上final
之所以可以不加final了,主要是因为那个Lamde与方法引用一起出现所造成的新局面
*/
/* anonymousInternal 匿名内部类
匿名内部类的使用
内容
匿名内部类 = 没有名字的内部类
任何的技术出现都有它可以解决的问题,所以下面首先来分析一下没有匿名内部类的情况
范例:观察程序代码的问题
interface A{// 定义了一个接口
public void ptintA();
}
class X implements A{
public void ptintA(){
System.out.println("AAAAAAAAAAAAAAA");
}
}
publlic class anonymousInternal{
publlic static void main(String args[]){
A a = new X();
a.ptintA();
}
}
有了一个接口,而后为接口定义了一个子类,在主类中利用对象的向上转型进行对象实例化操作
但是现在有一个问题出现了,本程序中为接口A定义了一个子类X,但是假设说此时的这个X子类只使用唯一的一次
那么有必要将其定义成一个单独的类吗?那么此时的设计就有些夸张了。
那么就可以利用匿名内部类的概念来解决,而且匿名内部类必须以抽象类或接口为前提进行使用
范例;使用匿名内部类
interface A{// 定义了一个接口
public void ptintA();
}
public class anonymousInternal{
public static void main(String args[]){
A a = new A(){ // 匿名内部类
public void ptintA(){
System.out.println("***********************");
}
}
a.ptintA();
}
}
现在的基本感觉此语法很槽糕,程序的结构很混乱
范例:
abstract class AbstractA{
private String mdg = "+++++++++++++";
public String getMsg(){
return this.msg;
}public abstract void print();
}
public class anonymousInternal{
public static void main(String args[]){
AbstractA a = new AbstractA(){ // 匿名内部类
public void ptint(){
System.out.println(this.getMsg());
}
}
a.ptintA();
}
}
匿名内部类的最大特点是可以减少类的定义个数,所以在以后的开发之中会大量的使用匿名内部类来进行某些接口子类的定义
这一点在后面讲解的多线程开发之中非常有用处,同时匿名内部类也是 Lembda 表达式的原始雏形
总结
可以看懂匿名内部类就够了,其他的慢慢随着代码的编写经验的增长自然就会了
*/
/* 总结
1.不要去考虑怎么用,一般的开发很少会用到,但是会使用
2.内部类先看明白它的语法形式
*/
菜鸡的Java笔记 第二十六 - java 内部类的更多相关文章
- 菜鸡的Java笔记 第二十八 - java 包的定义
包的主要作用以及定义 包的导入操作 系统常见的开发包 jar 程序命令 包的定义 在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...
- 菜鸡的Java笔记 第十六 - java 引用传递
referenceDelivery 引用传递是整个java 的精髓,也是所有初学者最难学的地方 引用的本质:同一块堆内存可以被不同的栈内存所指向 下面通过三道程序来进行引用传 ...
- 菜鸡的Java笔记 第二十四 - java 接口的基本定义
1.接口的基本定义以及使用形式 2.与接口有关的设计模式的初步认识 3.接口与抽象类的区别 接口与抽象类相比,接口的使用几率是最高的,所有的 ...
- 菜鸡的Java笔记 第二十二 - java 对象多态性
本次只是围绕着多态性的概念来进行讲解,但是所讲解的代码与实际的开发几乎没有关系,而且多态一定是在继承性的基础上才可以操作的, 而本次将使用类继承的关系来描述多态的性质,实际的开发中不会出 ...
- 菜鸡的Java笔记 第二十九 - java 单例设计模式
SingleCase 单例设计模式 1.单例设计模式的特点 2.多例设计模式的特点 内容 单例设计模式 现在如果说有这么一个程序类 class S ...
- “全栈2019”Java多线程第二十六章:同步方法生产者与消费者线程
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 菜鸡的Java笔记 第二十五 wrapperClass 包装类
wrapperClass 包装类 1.包装类的特点 2.装箱与拆箱操作 3.数据转型处理 内容 Object 类可以接收 ...
- 菜鸡的Java笔记 第二十 - java 方法的覆写
1.方法的覆写 当子类定义了与父类中的完全一样的方法时(方法名称,参数类型以及个数,返回值类型)这样的操作就称为方法的覆写 范例:观察方法的覆写 class A{ public void ...
- 菜鸡的Java笔记 第十九 - java 继承
继承性的主要目的,继承的实现,继承的限制 继承是面向对象中的第二大主要特点,其核心的本质在于:可以将父类的功能一直沿用下去 为什么需要继承? ...
随机推荐
- NOIP 模拟 七十一
最后一场多校模拟赛,好像是信心赛??不过考的不行..最近难题比较多,对题目的难度把握不够好,经常出现简单题跳过的现象. 100+100+20+40 T1 签到题(qiandao) 如果一个点的度数不是 ...
- 左手IRR,右手NPV,掌握发家致富道路密码
智能手机的普及让世界成为了我们指尖下的方寸之地. 在各种信息爆炸出现的同时,五花八门的理财信息与我们的生活越贴越近.投资不再仅仅是企业行为,对于个人而言,也是很值得关注的内容. 但是落脚到很小的例子之 ...
- Linux虚拟机配置静态ip地址
使用VMware搭建的虚拟机ip地址经常变动,在这里记录一下虚拟机设置静态ip地址: 首先通过VMware菜单栏编辑->虚拟网络编辑器->NAT设置查看子网ip地址和网关ip: 例如我这里 ...
- 9.亿级流量电商系统JVM模型参数预估方案
1. 需求分析 大促在即,拥有亿级流量的电商平台开发了一个订单系统,我们应该如何来预估其并发量?如何根据并发量来合理配置JVM参数呢? 假设,现在有一个场景,一个电商平台,比如京东,需要承担每天上亿的 ...
- Python基础 | 字符串格式化输出及print()函数介绍
在写代码时,我们会经常与字符串打交道,Python中控制字符串格式通常有三种形式,分别是使用str%,str.format(),f-str,用法都差不多,但又有一些细微之差. 一起来看看吧~~~ 一. ...
- 洛谷4172 WC2006水管局长(LCT维护最小生成树)
这个题和魔法森林感觉有很相近的地方啊 同样也是维护一个类似最大边权最小的生成树 但是不同的是,这个题是有\(cut\)和询问,两种操作.... 这可如何是好啊? 我们不妨倒着来考虑,假设所有要\(cu ...
- 2020.5.4-ICPC Pacific Northwest Regional Contest 2019
A. Radio Prize All boring tree-shaped lands are alike, while all exciting tree-shaped lands are exci ...
- git常用的一些简单命令
1.如果一个文件被修改了,但是还没有使用 git add 命令,此时想取消这次修改,需要执行的命令如下: git checkout -- 文件名 2.如果一个文件执行了 git add ,此时想取消这 ...
- CSP踩被记
本来想起个清新脱俗的标题,但碍于语文功底不行,于是光明正大嫖了LiBoyi的高端创意,把这篇博客命名为踩被记. Day -6 用假暴力把真正解拍没了,伤心.Rp有点低 Day -4 信息学考,\(py ...
- 多边形——————区间dp
原题链接:https://www.acwing.com/problem/content/285/ 题意简单来说就是:给你一个环,断掉一条边使其成为一个链,用这个链跑dp,求最大得分. 首先这不是一道板 ...