菜鸡的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 继承
继承性的主要目的,继承的实现,继承的限制 继承是面向对象中的第二大主要特点,其核心的本质在于:可以将父类的功能一直沿用下去 为什么需要继承? ...
随机推荐
- Java集合——List,Set,Map总结笔记
1. 集合 Collection 1.1 Java 集合框架 Java 集合框架位于 java.util 包中.Java 集合框架主要包括两种类型的容器,一种是集合(C ...
- 解决Vite-React项目中js使用jsx语法报错的问题
背景 在做存量项目接入Vite测试时发现,存量(老)项目中很多是直接在js中书写jsx语法,使用Vite启动时就会抛出一堆问题Failed to parse source. 不嫌麻烦可以跑个脚本批量修 ...
- k8s学习笔记(2)- Rancher2.x部署springboot应用及高可用、扩容
前言:上一篇介绍基于k3s环境,使用kubectl部署springboot简单项目应用,本篇介绍基于rancher2.x部署应用程序 1.上篇已部署一个springboot应用,我们可以通过ranch ...
- C 库函数源码
github URL git://sourceware.org/git/glibc.git 码云 URL https://gitee.com/jason.R.xie/glibc.git
- Python常用加密解密算法
MD5加密 简介 这是一种使用非常广泛的加密方式,不可逆的,常见16位和32位一般都是md5 实现 import hashlib data = '你好' print(hashlib.md5(data. ...
- ubuntu修改软件源的方法
最快方法--替换法 刚安装好的ubutun,打开source.list后,用vim替换的方法将所有的us提付出替换为 cn,然后保存退出,更新即可. # vim /etc/apt/source.lis ...
- CSP-J 2021 复赛游记
Day-1 啥也没干 晚上看了看洛谷的讨论,据说freopen在打开的最后要加 fclose(stdin);fclose(stdout); 不加也可.不过据说Linux在return 0之前不会自动关 ...
- Convolutional Neural Network-week2编程题2(Residual Networks)
1. Residual Networks(残差网络) 残差网络 就是为了解决深网络的难以训练的问题的. In this assignment, you will: Implement the basi ...
- CODING 助力江苏高速信息实现组织敏捷与研发敏捷,领跑智慧交通新基建
疫情之下的高速公路管控重任 江苏高速公路信息工程有限公司(以下简称:江苏高速信息)成立于 2002 年,是江苏交通控股旗下,专业从事高速公路领域机电系统集成.智能交通软硬件研发.大数据分析运营的高新技 ...
- 2021.9.22考试总结[NOIP模拟59]
T1 柱状图 关于每个点可以作出两条斜率绝对值为\(1\)的直线. 将绝对值拆开,对在\(i\)左边的点\(j\),\(h_i-i=h_j-j\),右边则是把减号换成加号. 把每个点位置为横坐标,高度 ...