fantasticDream

面向对象编程----内部类详解

内部类innerclasses在一个类的里面定义另一个类

一般情况,我们把类定义成独立的单元有些情况下,我们把一个类放在另一个类的内部定义,称为内部类。

 

内部类的作用:

  1. 内容类提供了更好的封装,只能让外部类直接访问不允许同一个包中的其他类直接访问。
  2. 内部类可以直接访问外部类的私有属性内部类你也可以看做外部类的一个成员),内部类被当成其外部类的成员但外部类不能访问内部类的内部属性。

 

内部类的使用场合:

由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性,所以,通常内部类在只为所在外部类提供服务的情况下优先使用。

 

内部类的分类:

  1. 成员内部类(可以使用privateprotetedpublic 任意进行修饰

    类文件:外部类$内部类.class

A) 非静态内部类外部类型使用非静态内部类和平时使用其他类没什么不同)

  1. 非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象非静态内部类对象单独属于外部类的某个对象
  2. 非静态内部类可以使用外部类的成员但是外部类不能直接访问非静态内部类成员
  3. 非静态内部类不能有静态方法、静态属性、静态初始化块。
  4. 静态成员不能访问非静态成员外部类的静态方法、静态代码块不能直接访问非静态内部类,包括不能直接使用非静态内部类定义变量、创建实例。
  5. 成员变量访问要点:
    1. 内部类里方法的局部变量:变量名
    2. 内部类属性:this变量名
    3. 外部类属性:外部类名.this变量名
    4. 内部类的访问:
      1. 外部类中定义内部类:new innerClass()
      2. 外部类及以外的地方使用非静态内部类

Outer.inner  varname = OuterObject.new inner()

Face.Nose nose = new Face().new Nose();

Face f2 = new Face();

Face.Nose nose2 = f2.new Nose();

b) 静态内部类

i. 定义方法:

Static class ClassName{

//类体

}

Ii. 使用要点:

  1. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。因此,静态内部类的实例方法不能直接访问外部类的实例方法。
  2. 静态内部类看做外部类的一个静态成员因此,外部类的方法中可以通过:静态内部类 名字 访问静态内部类的静态成员。通过new静态内部类()访问静态内部类的实例。
  3. 在外部类的外面创建静态内部类:

  Face.TestStaticInner aInner = new Face.TestStaticInner();

2.匿名内部类

适合那种只需要使用一次的类比如:键盘监听操作等等。语法

new 父类构造器(实参类表)实现接口(){

//匿名内部类类体!

}

this.addWindowListener(new WindowAdapter(){

@override

public void windowClosing(WindowEvent e){

System.exit(0);

}

});

This.addKeyListener(new KeyAdapter(){

@override

public void keyPressed(KeyEvent e){

//YCDO Auto--generated method stub

myTank.keyReleased(e);

}

});

局部内部类

定义在方法内部。作用域只限于本方法。用的非常少。

package com.bjsxt.aleven;
import java.util.Scanner;
//import com.bjsxt.aleven.Face.Nose;
/**
* 测试静态内部类
* @author 神奇的梦
*
* 普通的成员内部类可以访问外部类的普通的属性和方法
* 普通的成员内部类可以看做外部类的普通的属性
* 普通内部类必须寄宿在外部类里面
*
* 静态内部类呢!
*
* 静态内部类的外部对象不一定要存在,外部类都不一定有,不能直接访问外部类的相关属性
* 但是静态内部类可以直接访问外部类的静态属性和方法
*/
public class Outer {
public static void main(String[] args) {

/*
调用非静态方法(也叫成员方法)
比如方法叫int publicMethodB(),
就必须先创建这个对象再调用其方法,例如:
int result2 = new OtherClass().publicMethodB();*/
/**
* 因为它的内部类对象是寄存在外部类对象里面的,
* 所以必须先有外部类对象才能有内部类对象
*/
// Nose n = new Nose();
// 第一种 这种需要import导入Face外部类里面的内部类Nose(同一个文件内也需要)
// import com.bjsxt.aleven.Face.Nose;
// Face f = new Face();
// 在f变量里面new它的内部类
// Nose n = f.new Nose();
// 第二种 这种不需要import导入Face外部类里面的内部类Nose也可以
// Face.Nose是类型
// 执行完 javac Outer.java后编译的class文件
// 内部类Nose的文件名为Face$Nose外部类和内部类之间用$隔开
// (内部类的一个字节码文件的名字)
/**
* 非静态内部类必须寄存在一个外部类对象里。
* 因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。
* 非静态内部类对象单独属于外部类的某个对象。
*/

 在外部类的外面创建内部类
// Face fa = new Face();
// Face.Nose no = fa.new Nose();
// 内部类可以调用外部类的内容
n.breath();
在外部类的外面创建静态内部类
Face.Ear e=new Face.Ear();
e.listen();
/**
* 调用静态方法的语法是,
* 类名.方法名(参数...)
*/
// Face.tet();
Face.tete();
}
}

class Face{
int type=20;
String shape="瓜子脸!";
static String color="红润";
static void sss() {

// 静态成员不能直接访问非静态成员:外部类的静态方法、静态代码块不能直接访问非静态内部类,包括不能直接使用非静态内部类定义变量、创建实例。
// 静态成员访问非静态成员

第一种

 

Face face =new Face();
face.ss();
Nose nn=face.new Nose();
System.out.println(nn.egg);

第二种

// 在外部静态方法中定义非静态内部类对象后,就可以访问
Face.Nose n = new Face().new Nose();
n.breath();

System.out.println("sss");
}

void ss() {

// 外部类中定义静态内部类

// 外部类不能直接访问非静态内部类成员
// 在外部方法中定义内部类对象后,就可以访问
// 第一种
Face.Nose n = new Face().new Nose();
System.out.println(n.egg);
// 第二种
Nose nose = new Nose();
System.out.println(nose.egg);
System.out.println();

// 第三种
Face f = new Face();
Face.Nose nn = f.new Nose();
System.out.println(nn.egg);

}

// 内部类
// 非静态内部类可以使用外部类的成员,
// 但是外部类不能直接访问非静态内部类成员。
class Nose{
// 普通成员内部类只能定义普通的成员跟方法
// 如果内部类没有重复的变量,会直接找到外部类变量
// int type=10;
// shape从属于堆里面的对象
String shape="瓜子脸";
// this.type访问的是我们自己Nose的type
// Face.this.type访问的是外部类Face的type
// 可以定义方法,不可以定义静态方法
// Nose类是从属于外部类对象的 Static是从属于类的
// 非静态内部类不能有静态方法、静态属性、静态初始化块。
/* static */ void breath() {
System.out.println(shape);
System.out.println(Face.this.type);
System.out.println("呼吸!");
}
}
// static属于类里面的
// 静态内部类看做外部类的一个静态成员
// static静态类从属于类,并没有继承 (建模版) 在对象里面
/**
* 外部类的静态方法、
* 静态代码块不能访问非静态内部类,
* 包括不能使用非静态内部类定义变量、创建实例。
*/
static class Ear{
void listen() {
// 当一个静态内部类对象存在,并不一定存在对应的外部类对象。
// 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
// 不能对非静态场形进行静态参考
// System.out.println(shape);
// 内部静态类可以访问外部静态属性和方法
sss();
// 内部静态类可以访问外部静态属性和方法
System.out.println(color);

在静态内部类中定义外部类对象后,就可以访问非静态外部类
Face face=new Face();
face.ss();

System.out.println("我在听!");
}
}
/**
* 测试键盘输入
* Scanner属于java.util包
*/

匿名内部类

// 调用构造器,传参System.in接收键盘的输入
// 调用原本java.util包里面存在的类直接构造出来就可以用了

public static void tet() {
// Resource leak: 's' is never closed
// 资源泄漏: “ s”永远不会关闭
Scanner s= new Scanner(System.in);
// 输入你的字符串,返回你的字符串。 程序运行到next会阻塞,等待键盘的输入!
String str=s.next();
// 此处输入后显示:调用str变量!
System.out.println("刚才键盘输入"+str);
}
// 错误实例
public static void teta() {
Scanner w=new Scanner(System.in);
System.out.println("亲输入第一个数:");
String see=w.next();
System.out.println("请输入第二个数");
String se=w.next();
// 此行上的多个标记-不能从 string 转换为 int 类型不匹配:
// 不能从 int 转换为 string-不能从 string 转换为 int
// String we=(int)(see)+(int)(se);
// System.out.println("两数之和为:"+we);
}
public static void tete() {
/**
* Scanner 类其实就是专门为在命令式界面中提供的一种输入类,
* Scanner 类位于java.util 包中, 其中还有更多常用的其他方法
* 例如:
* nextLine() 输入一行数据,一般会将你输入的数据当做字符串处理
* nextDouble() 输入一个双精度实型的数据
* nextFloat() 输入一个单精度实型的数据
* nextByte() 输入一个字节的数据
* nextLong() 输入一个long型的数据,
*
* 如果输入错误的话, 或者输入的东西和你调用的方法不匹配,
* 都会抛出InputMismatchException 异常
*/
// 资源泄漏: “ w”永远不会关闭
Scanner w new Scanner(System.in);
System.out.println("亲输入第一个数:");
/**
* nextInt
* 其意思是使用Scanner 类中的nextInt() 方法输入一个整数,
* 该方法只是接受一个整型的数据,如果输入的是非整数数据,
* 将会抛出 InputMismatchException 异常,
*/

//使用输入流对象调用nextInt() 方法输入一个整数到userNum中
// int userNum=w.nextInt();
// 读取数字也可以使用nextLine(),不过需要转换:Integer.parseInt(w.nextLine())
int userNum=Integer.parseInt(w.nextLine());
System.out.println("请输入第二个数");
// int se=w.nextInt();
int se=Integer.parseInt(w.nextLine());
int we=userNum+se;
System.out.println("两数之和为:"+we);
}
public static void tetet() {

Scanner input = new Scanner(System.in);
System.out.println("输入数字");
int num = input.nextInt();
System.out.println("输入字符串");
String s = input.nextLine();
/**
* 运行结果就是,我输入完数字之后敲下回车,我还没输入字符串,程序就结束了。
* 原因就是,你在输入的时候,你输入的所有内容(包括空格和回车)都会存在缓冲区next()
* nextInt()这些会从缓冲区中读取你的输入但是在遇到空格或者回车的时候会停止,
* 不会将空格或者回车读入,而只有nextLine()会将空格和回车读入。
* 所以在我第一次输入数字并敲下回车后,这个回车并没有被nextInt()读入,
* 而是留在了缓冲区,并被nextLine()读到了这个回车,所以nextLine()直接就返回了,
* 程序会直接结束。
* 建议:改为next就可以了。
* ————————————————
* next()方法:
* 在读取内容时,会过滤掉有效字符前面的无效字符,
*对输入有效字符之前遇到的空格键、
*Tab键或Enter键等结束符,
*next()方法会自动将其过滤掉;
* 只有在读取到有效字符之后,
*next()方法才将其后的空格键、
*Tab键或Enter键等视为结束符;
*所以next()方法不能得到带空格的字符串。
* nextLine()方法:
* 该方法字面上有扫描一整行的意思,
*它的结束符只能是Enter键,
*即nextLine()方法返回的是Enter键之前没有被读取的所有字符,
*它是可以得到带空格的字符串的。
*/
}
}

posted on 2022-06-11 11:39  神奇的梦  阅读(72)  评论(0编辑  收藏  举报

导航