Input(读) Output(写)操作
File类
import java.io.File;
将操作系统中的文件、目录(文件夹)、路径、封装成File对象
提供方法,操作系统中的内容。File与系统无关的类。
String pathSeparator = File.pathSeparator;
System.out.println(pathSeparator); // windows';' Linux ':' 路径分割符
String separator = File.separator;
System.out.println(separator); // 斜线 / 目录的名称分割符 linux: \
 
构造方法
File(String pathName)
 
绝对路径
在系统中具有唯一性 如:c:\users\baidawei\downloads
 
相对路径
表示的是路径之间的相对关系 如: /downloads/  不需要考虑根级目录具体盘符
 
创建文件
File file = new File("c:\\Users\\baidawei\\Downloads\\o.txt");
if(!file.exists()){
    boolean result = file.createNewFile();
    System.out.println(result);
}
Mac:
File file = new File("/Users/baidawei/Desktop/test.txt");
boolean result = file.createNewFile();
System.out.println(result);
 
创建目录
boolean result = file.mkdir();
 
删除
boolean result = file.delete();
 
获取文件名或文件夹名
String fileName = file.getName(); //test.txt
 
获取文件路径
file.getPath() // /Users/baidawei/Desktop/test.txt
 
获取文件字节长度
file.length()
 
获取绝对路径 返回字符串
file.getAbsolutePath() // /Users/baidawei/Desktop/test.txt
 
获取绝对路径 返回file类
file.getAbsoluteFile()  // /Users/baidawei/Desktop/test.txt
 
获取父路径 返回字符串
file.getParent() // /Users/baidawei/Desktop
 
获取父路径 返回File类
file.getParentFile() // /Users/baidawei/Desktop
 
文件或目录是否存在
file.exists() // boolean
 
判断是否是目录
file.isDirectory() // boolean
 
获取路径中的文件和文件夹名 返回String[]
for(String str : file.list()){
    System.out.println(str);
}
 
获取路径中的文件和文件夹名 返回File[]
for(File f : file.listFiles()){
    System.out.println(f.getName());
}
 
过滤器 
for (File f : file.listFiles(new myFilter())) {
    System.out.println(f.getName());
}
 
class myFilter implements FileFilter {
    @Override
    public boolean accept(File pathname) {
        if(pathname.isDirectory()){
            return true;
        }
        return false;
    }
}
 
递归获取全文件
public static void main(String[] args) {
File file = new File("F://");
getAllDir(file);
}
 
public static void getAllDir(File dir) {
if (dir.listFiles() != null) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
getAllDir(f);
} else {
System.out.println(f);
}
}
}
}
 
字节流
字节输出流 OutputStream 所有输出流父类
常用方法:
write(int b) 写入1个字节
write(byte[] b) 写入字节数组
write(byte[] b,int ,int) 写入字节数组,int 开始写入的索引, int 写几个
close() 关闭流对象,释放与流相关的资源
 
FileOutputStream 写入数据文件 OutputStream的子类
FileOutputStream fos = new FileOutputStream("F://text.txt");
fos.write(97);
fos.write(98);
fos.write(99);
fos.close();
没有就创建,有就覆盖 abc
 
byte[] bytes = {65,66,67,68,69,70};
fos.write(bytes);//ABCDEF
fos.close();
 
byte[] bytes = {65,66,67,68,69,70};
fos.write(bytes,1,2);//BC
fos.close();
 
写字符串
String strs = "Hello Word \r\n my name is david"; // 换行\r\n 
byte[] bytes = strs.getBytes();
fos.write(bytes);
fos.close();
 
续写文件,FileOutputStream构造方法第二个参数设置为true 就不会覆盖了
FileOutputStream fos = new FileOutputStream("F://text.txt",true);
 
字节输入流 InputStream 所有字节输入流的父类
读取任意文件,每次只读取1个字节。
read(int b) 读取1个字节
read(byte[] b) 读取字节数组
close() 关闭流对象
 
FileInputStream 读取数据文件 InputStream子类
 
读取字节:
public static void main(String[] arg) throws IOException {
FileInputStream fis = new FileInputStream("F://text.txt");
int len = 0;
while((len=fis.read()) != -1){ // -1就是没了
System.out.println(len); //输出字节 len代表执行一次
}
fis.close();
}
 
读取字节数组(字符串):
 
public static void main(String[] arg) throws IOException {
FileInputStream fis = new FileInputStream("F://text.txt");
byte[] b = new byte[1024];
int len = 0;
while((len=fis.read(b)) != -1){
System.out.print(new String(b,0,len)); //调用String构造方法 参数 字节数组
}
 
fis.close();
}
 
复制文件
字节复制 效率低
FileInputStream fis = new FileInputStream("F:\\text.txt");
FileOutputStream fos = new FileOutputStream("F:\\copy\\text.txt");
 
int len = 0;
while((len=fis.read()) != -1){
fos.write(len);
}
fis.close();
fos.close();
 
字节数组赋值 提高效率
FileInputStream fis = null;
FileOutputStream fos = null;
 
try{
fis = new FileInputStream("F:\\text.txt");
fos = new FileOutputStream("F:\\copy\\text.txt");
 
int len = 0;
byte[] b = new byte[1024];
while((len=fis.read(b)) != -1){
fos.write(len);
}
}catch(Exception ex){
System.out.print(ex.getMessage());
}finally {
fis.close();
fos.close();
}
 
FileWriter类 字符输出流 写文本
write(int c) 写1个字符
write(char[] c) 写字符数组
write(char[] c,int ,int)字符数组,开始索引,多少个
write(String s) 写字符串
 
FileWriter fw = new FileWriter("F:\\text.txt");
//写1个字符
fw.write(100);
//最好写一次刷一次,释放内存
fw.flush();
//写1个字符数组
fw.write(new char[]{99,98,97,96});
//写1个字符数组 1开始 3个
fw.write(new char[]{99,98,97,96},1,3);
//写字符串
fw.write("有一个姑娘,他有一些嚣张");
//刷新 write一次 刷新一次
fw.flush();
//关闭
fw.close();
续写 构造方法第二个参数true
FileWriter fw = new FileWriter("F:\\text.txt",true);
 
FileReader累 字符输入流 读取文本
FileReader fr = new FileReader("F:\\text.txt");
//读1个字节
int len = 0;
while((len=fr.read()) != -1){
System.out.print((char)len);
}
fr.close();
 
读取字符数组
char[] c = new char[1024];
int len = fr.read(c);
System.out.println(new String(c,0,len));
fr.close();
 
转换流
解决乱码问题
因为写文件时会默认本机编码表,GBK,美国机器打开就会乱码。
 
使用OutputStreamWriter(OutputStream out) 读取文件可以指定编码类型
FileOutputStream fos = new FileOutputStream("/Users/baidawei/Desktop/gbk.txt");
//使用转换流指定编码表
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK"); //默认GBK可以不写
osw.write("你好");
osw.flush();
osw.close();
 
使用UTF-8编码表
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
 
UTF-8 编码表中 一个汉字3个字节。
 
使用InputStreamReader类写入文件指定编码类型。
//如果编码格式不一致则会乱码
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/baidawei/Desktop/utf.txt");
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
int len = 0;
while((len=isr.read()) != -1){
System.out.println((char)len);
}
fis.close();
}
 
缓冲流
提高读写速度、效率。
 
字节输出流的缓冲流 BufferedOutputStream(OutputStream out)
FileOutputStream fos = new FileOutputStream("/Users/baidawei/Desktop/gbk.txt");
//使用缓冲流
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("加班中...".getBytes());
bos.close();
 
字节输入流的缓冲流 BufferedInputStream(InputStream input)
FileInputStream fis = new FileInputStream("/Users/baidawei/Desktop/gbk.txt");
//使用缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
int len = 0;
byte[] b = new byte[1024];
while((len=fis.read(b)) != -1){
System.out.print(new String(b,0,len));
}
 
字符输出流缓冲流BufferedWriter
public static void main(String[] args) throws IOException {
String url = "/Users/baidawei/Desktop/test.txt";
FileWriter fw = new FileWriter(url);
BufferedWriter bfw = new BufferedWriter(fw);
bfw.write("测试bufferedWriter输出流缓冲流");
bfw.flush();
//特有换行方法
bfw.newLine();
bfw.write("newline好使么?");
bfw.flush();
bfw.close();
}
 
字符输入流缓冲流BufferedReader
public static void main(String[] args) throws IOException {
String url = "/Users/baidawei/Desktop/test.txt";
FileReader fr = new FileReader(url);
BufferedReader br = new BufferedReader(fr);
 
String line = null;
 
while((line = br.readLine()) != null){
//特有方法 读取一整行 返回字符串 不包含\r\n换行符号
System.out.println(line);
}
}
 
复制
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("/Users/baidawei/Desktop/test.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/baidawei/Desktop/test_bak.txt"));
 
String line = null;
 
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
 
Properties类
Properties类是Hashtable的子类,实现Map接口,Hashtable是线程不安全的被Hashmap替换。
键值对 都是字符串,可以和IO对象结合使用,实现持久化存储(可以存储到硬盘、u盘、光盘)上。
Properties pp = new Properties();
//存入 等同于put 区别只能字符串
pp.setProperty("key","value");
pp.setProperty("yu","datou");
System.out.println(pp);
 
//通过key获取value
String val = pp.getProperty("yu");
System.out.println(val);
 
//获取所有key
for(String s :pp.stringPropertyNames()){
System.out.println(pp.getProperty(s));
}
 
load() 加载方法
Properties pp = new Properties();
//.properties 后缀为 键值对配置文件
FileReader fr = new FileReader("/Users/baidawei/desktop/test.properties");
pp.load(fr);
System.out.println(pp);
fr.close();
 
test.properties文件格式固定 必须这样 不能加空格 分号
name=zhagnsan
age=18
#email=853020304@qq.com
#后面是注视
 
store() 保存方法
Properties pp = new Properties();
pp.setProperty("firstname","zhagn");
pp.setProperty("lastname","san");
pp.setProperty("email","83@qq.com");
FileWriter fw = new FileWriter("/Users/baidawei/desktop/test.properties");
pp.store(fw,"yuanyin buneng zhognwen"); //写中文会转换为unicode编码表存储
fw.close();
对象的序列化
对象中的数据new Person();以流的形式写入到文件中保存的过程称为写出对象。
ObjectOutputStream 写出对象 对象的序列化
//类需要实现Serializable接口
public class Person extends Object implements Serializable {
private String name;
private int age;
 
Person(String name){
this.name = name;
}
 
Person(String name,int age){
this(name);
this.age = age;
}
 
@Override
public String toString(){
return "Person[name" + name + ", age =" + age +"]";
}
}
 
Person p = new Person("name",18);
FileOutputStream fos = new FileOutputStream("/Users/baidawei/desktop/oos.text");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.close();
fos.close();
 
ObjectInputStream 读取对象 对象的反序列化
FileInputStream fis = new FileInputStream("/Users/baidawei/desktop/oos.text");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
System.out.println(obj);
ois.close();
 
属性值静态的 static 不能序列化
属性值 加transient关键字 阻止序列化
 
Serializable接口 没有抽象方法 只是一个标记
 
打印流
只负责数据目的输出
PrintStream
接收File类型,字符串文件名,OutputStream输出流
PrintWriter
//输出目的FIle
public static void printStream_file() throws FileNotFoundException {
File file = new File("/Users/baidawei/desktop/myTest.txt");
PrintWriter pw = new PrintWriter(file);
pw.println("啥意思啊"); //原样输出
pw.println("啥意思啊嗯?");
pw.flush();
pw.close();
}
 
//输出String文件名
public static void printWriter_fileName() throws FileNotFoundException{
PrintWriter pw = new PrintWriter("/Users/baidawei/desktop/myTest2.txt");
pw.println("hahahehehhe");
pw.println("hahahhaha");
pw.flush();
pw.close();
}
 
//输出OutputStream 输出流对象可以 开启自动刷新
public static void printWriter_outputStream() throws FileNotFoundException{
PrintWriter pw = new PrintWriter(new FileOutputStream("/Users/baidawei/desktop/myTest3.txt"),true);
pw.println("333");
pw.println("444");
pw.flush();
pw.close();
}
 
commons-io工具类
简化File操作类
下载后 在Idea中选择File->Project Structure->Dependencies->加号->JARs or directories->ok->External Libraries中就出现了
FilenameUtils类
String url = "/Users/baidawei/Desktop/myTest.txt";
 
//获取文件扩展名
String ext = FilenameUtils.getExtension(url);
System.out.println(ext); //txt
 
//获取文件名
String fileName = FilenameUtils.getName(url);
System.out.println(fileName); ///myTest.txt
 
//是否是txt文件
boolean isExtens = FilenameUtils.isExtension(url,"txt");
System.out.println(isExtens);
 
FileUtils类
String url = "/Users/baidawei/Desktop/haha.txt";
 
//读取文件 返回String
String s = FileUtils.readFileToString(new File(url));
System.out.println(s);
 
//写String到文件
FileUtils.writeStringToFile(new File("/Users/baidawei/Desktop/haha.txt"),"字符串 要写的内容");
 
//复制文件
FileUtils.copyFile(new File("/Users/baidawei/Desktop/haha.txt"),new File("/Users/baidawei/Desktop/new.txt"));
 
//复制文件夹 macnew
FileUtils.copyDirectory(new File("/Users/baidawei/Downloads/mac"),new File ("/Users/baidawei/Downloads/macnew"));
 
//复制到目标文件里面去 macnew/mac
FileUtils.copyDirectoryToDirectory(new File("/Users/baidawei/Downloads/mac"),new File ("/Users/baidawei/Downloads/macnew"));
 
多线程
进程:当一个程序进入内存运行,就变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。 如 迅雷软件运行中
线程:线程是进程的一个执行单元,负责当前继承中的程序执行,一个进程中至少有一个线程,可以有多个线程。 如迅雷软件中 同时下载3个任务
 
程序运行原理
分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
抢占式调度:优先让优先级高的线程使用CPU,如果线程优先级相同,那么会随机选择一个,Java使用的为抢占式调度。
 
Main方法是主线程
public static void main(String[] args) {
SayHi();
System.out.println("===========================单线程======================");
}
 
public static void SayHi() {
for (int i = 0; i < 100000; i++) {
System.out.println(i);
}
}
需要等待10万次执行结束后 才能执行 最下面的输出。
 
Thread类
Thread类是程序中的线程类,允许应用程序并发地运行多个执行线程。
创建执行线程有两种方法,
1:继承Thread类,重写run方法 创建对象,开启线程,run方法相当于其他线程的main方法。
2:实现Runnable接口,重写run方法。创建runnable的子类对象,传入到某个线程的构造方法中,开启线程。
方法一继承Thread类:
public class SubThread extends Thread {
@Override
public void run() {
for(int i = 1;i<50;i++){
System.out.println(i+"A");
}
}
}
//并发执行 一起循环
public class Main {
public static void main(String[] args) {
SubThread st = new SubThread();
st.start();//运行子类 run方法
for (int i = 0; i < 50; i++) {
System.out.println(i);
}
}
}
 
获取线程的名字
public class SubThread extends Thread {
@Override
public void run() {
for(int i = 1;i<50;i++){
//获取线程的名字 父类的方法
System.out.println(getName());
System.out.println(i+"A");
}
}
}
 
Thread.currentThread().getName() //当前线程的名字
程序主线程名字:main,自定义的线程:Thread-0、Thread-1数字顺延 也可以使用setName()自定义线程名称
sleep()方法 睡眠多少毫秒在执行
 
方法二:实现Runnable接口
public class SubThread implements Runnable {
@Override
public void run() {
for(int i = 1;i<50;i++){
System.out.println(i+"A");
}
}
}
public static void main(String[] args) {
SubThread st = new SubThread();
Thread th = new Thread(st);
th.start();
for (int i = 0; i < 50; i++) {
System.out.println(i);
}
}
 
线程池
线程池是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
实现Runnable接口
public class ThreadPoolRunnable implements Runnable {
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
//创建线程池对象 包含2个线程对象
ExecutorService es = Executors.newFixedThreadPool(2);
//从线程池创建对象
es.submit(new ThreadPoolRunnable());
es.submit(new ThreadPoolRunnable());
 
多线程 安全问题
//并发问题 同时判断为true 执行了多次
SubThread st = new SubThread();
 
Thread t0 = new Thread(st);
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
 
t0.start();
t1.start();
t2.start();
 
public class SubThread implements Runnable {
 
private int count = 1;
 
@Override
public void run() {
while(true){
if(count > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售第:" + --count);
}
}
}
}
 
解决线程安全:
1.同步代码块 synchronized(锁对象)
用于解决线程安全问题,同步执行,第一个线程执行完后再执行下一个线程。多个线程时,使用同一个锁对象才能够保证线程安全。
//lock是定义的一个object 对象
synchronized (lock){
if(count > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售第:" + --count);
}
}
 
2.同步方法 synchronized 不需要写锁对象 是本类对象this
public synchronized void method(){
//可能会产生线程安全问题的代码
}
 
Lock接口
Lock实现了比使用synchronized方法和语句获得更广泛的锁定操作。
实现类 ReentrantLock
lock() 锁
unlock() 释放锁
 
public void run() {
while (true) {
lock.lock(); //锁住
if (count > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售第:" + --count);
}
lock.unlock(); //释放
}
}
}
 
线程的死锁
当线程任务出现了多个同步(多个锁)时,如果同步中潜逃了其他的同步,这时容易引发一种现象:程序出现无限等待,这种现象称之为死锁。
synchronzied(A锁){
synchronized(B锁){
 
}
}
 
线程等待与唤醒
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
 

Java IO流对象、多线程的更多相关文章

  1. Java—IO流 对象的序列化和反序列化

    序列化的基本操作 1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中 ...

  2. Java——IO流 对象的序列化和反序列化流ObjectOutputStream和ObjectInputStream

    对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息. 对象信息一旦写到文件上那么对象的信息就可以做到持久化了 对象的输出流: ObjectOutputStream 对象的输入流:  Ob ...

  3. java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  4. Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  5. Java IO流详尽解析

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  6. JAVA.IO流学习笔记

    一.java.io 的描述 通过数据流.序列化和文件系统提供系统输入和输出.IO流用来处理设备之间的数据传输 二.流 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数 ...

  7. 【转载】JAVA IO 流的总结

    来自http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html,写的很详细 Java流操作有关的类或接口: Java流类图结构: 流的概念和 ...

  8. Java IO流学习总结(转)

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  9. Java IO流学习总结(1)

    Java IO流学习总结 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本 ...

随机推荐

  1. C++ 仿函数/函数指针/闭包lambda

    在上一篇文章中介绍了C++11新引入的lambda表达式(C++支持闭包的实现),现在我们看一下lambda的出现对于我们编程习惯的影响,毕竟,C++11历经10年磨砺,出140新feature,对于 ...

  2. python的IndentationError: unexpected indent python

    都知道python是对格式要求很严格的,写了一些python但是也没发现他严格在哪里,今天遇到了IndentationError: unexpected indent错误我才知道他是多么的严格.    ...

  3. 如何设计一个web容器

    开发一个web容器涉及很多不同方面不同层面的技术,例如通信层的知识,程序语言层面的知识等等,且一个可用的web容器是一个比较庞大的系统,要说清楚需要很长的篇幅,本文旨在介绍如何设计一个web容器,只探 ...

  4. 《java入门第一季》之Integer类和自动拆装箱概述

    / * int 仅仅是一个基本类型.int有对应的类类型,那就是Integer.  * 为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型--包装类类型 ...

  5. 优雅的App完全退出方案(没有任何内存泄漏隐患)

    在Android开发过程中,特别是界面比较多的情况下,用平常的退出方式往往是不能完全退出这个应用,网络上也好多各种退出方案.其中一种应该是被广大开发者采纳使用,也非常的清晰方便,就是在Applicat ...

  6. 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  7. android微信登录,分享

    这几天开发要用到微信授权的功能,所以就研究了一下.可是微信开放平台接入指南里有几个地方写的不清不楚.在此总结一下,以便需要的人. 很多微信公众平台的应用如果移植到app上的话就需要微信授权登陆了. 目 ...

  8. Android热补丁技术—dexposed原理简析(手机淘宝采用方案)

    上篇文章<Android无线开发的几种常用技术>我们介绍了几种android移动应用开发中的常用技术,其中的热补丁正在被越来越多的开发团队所使用,它涉及到dalvik虚拟机和android ...

  9. 解决os x下gdb不能调试的问题

    在较新的os x中使用gdb调试程序会发生 Unable to find Mach task port 之类的错误,这是由于新的os x内核禁止未授权的程序随意控制其他进程,如果不用root权限的话, ...

  10. Java内部类与外部类

    错误提示: 没有任何类型 TestThread 的外层实例可访问.必须用类型 TestThread 的外层实例(例如,x.new A(),其中 x 是 TestThread 的实例)来限定分配. pu ...