字符流

  计算机并不区分二进制文件与文本文件。所有的文件都是以二进制形式来存储的,因此,

从本质上说,所有的文件都是二进制文件。所以字符流是建立在字节流之上的,它能够提供字符

层次的编码和解码。列如,在写入一个字符时,Java虚拟机会将字符转为文件指定的编码(默认

是系统默认编码),在读取字符时,再将文件指定的编码转化为字符。

常见的码表如下:

ASCII:           美国标准信息交换码。用一个字节的7位可以表示。

ISO8859-1:   拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,

藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。

GB2312:   英文占一个字节,中文占两个字节.中国的中文编码表。

GBK:      中国的中文编码表升级,融合了更多的中文文字符号。

Unicode:  国际标准码规范,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。

UTF-8:    最多用三个字节来表示一个字符。

(我们以后接触最多的是iso8859-1、gbk、utf-8)

查看上述码表后,很显然中文的‘中’在iso8859-1中是没有对映的编码的。或者一个字符在2中码表中对应的编码不同,例如有一些字在不同的编码中是有交集的,例如bjg5 和gbk 中的汉字简体和繁体可能是一样的,就是有交集,但是在各自码表中的数字不一样。

例如

使用gbk 将中文保存在计算机中,

中  国

对映  100  200   如果使用big5 打开

可能   ?  ...

不同的编码对映的是不一样的。

很显然,我们使用什么样的编码写数据,就需要使用什么样的编码来对数据。

ISO8859-1:一个字节

GBK: 两个字节包含了英文字符和扩展的中文   ISO8859-1+中文字符

UTF-8 万国码,推行的。是1~3个字节不等长。英文存的是1个字节,中文存的是3个字节,是为了节省空间。

那么我们之前学习的流称之为字节流,以字节为单位进行操作之情的操作全是英文,如果想要操作中文呢?

测试:将指定位置的文件通过字节流读取到控制台

public class TestIo {
public static void main(String[] args) throws IOException {
String path = "c:\\a.txt";
writFileTest();
readFileByInputStream(path);
} private static void readFileByInputStream(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
int len = 0;
while ((len = fis.read()) != -1) {
System.out.print((char) len);
}
}
private static void writFileTest() throws FileNotFoundException,
IOException {
// 创建文件对象
File file = new File("c:\\a.txt");
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(file);
fos.write("中国".getBytes());
fos.close();
}
}

发现控制台输出的信息:

???ú  是这样的东西,打开a.txt 文本发现汉字”中国”确实写入成功。

那么说明使用字节流处理中文有问题。

仔细分析,我们的FileInputStream输入流的read() 一次是读一个字节的,返回的是一个int显然进行了自动类型提升。那么我们来验证一下“中国”对应的字节是什么

使用:"中国".getBytes() 即可得到字符串对应的字节数组。是[-42, -48, -71, -6]

同样,将read方法返回值直接强转为byte ,发现结果也是-42, -48, -71, -6 。

public class TestIo {
public static void main(String[] args) throws IOException {
String path = "c:\\a.txt";
writFileTest();
readFileByInputStream(path);
//查看中国对应的编码
System.out.println(Arrays.toString("中国".getBytes()));
} private static void readFileByInputStream(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
int len = 0;
while ((len = fis.read()) != -1) {
System.out.println((byte)len);
}
} private static void writFileTest() throws FileNotFoundException,
IOException {
// 创建文件对象
File file = new File("c:\\a.txt");
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(file);
fos.write("中国\r\n".getBytes());
fos.close();
} }

那么中国 对应的是-42, -48, -71, -6是4个字节。 那就是一个中文占2个字节,(这个和编码是有关系的)

很显然,我们的中文就不能够再一个字节一个字节的读了。所以字节流处理字符信息时并不方便那么就出现了字符流。

  字节流是 字符流是以字符为单位。

  体验字符流:

public static void main(String[] args) throws IOException {

        String path = "c:\\a.txt";
readFileByReader(path);
}
private static void readFileByReader(String path) throws IOException {
FileReader fr = new FileReader(path);
int len = 0;
while ((len = fr.read()) != -1) {
System.out.print((char) len);
}
}

总结:字符流就是:字节流 + 编码表,为了更便于操作文字数据。字符流的抽象基类:

Reader , Writer。

由这些类派生出来的子类名称都是以其父类名作为子类名的后缀,如FileReader、FileWriter。

Reader:

方法:

1,int read():

读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.

2,int read(char[]):

将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1.

3,close()

读取字符其实用的是window系统的功能,就希望使用完毕后,进行资源的释放

public class IoTest1_Reader {

    public static void main(String[] args) throws Exception {
String path = "c:/a.txt";
// readFileByInputStream(path);
readFileByReader(path);
} /**
* 使用字节流读取文件内容
*
* @param path
*/
public static void readFileByInputStream(String path) throws Exception {
InputStream in = new FileInputStream(path); int len = 0;
while ((len = in.read()) != -1) {
System.out.print((char) len);
} in.close();
} /**
* 使用字符流读取文件内容
*/
public static void readFileByReader(String path) throws Exception {
Reader reader = new FileReader(path);
int len = 0;
while ((len = reader.read()) != -1) {
System.out.print((char) len);
} reader.close();
} }

Writer

Writer中的常见的方法:

1,write(ch): 将一个字符写入到流中。

2,write(char[]): 将一个字符数组写入到流中。

3,write(String): 将一个字符串写入到流中。

4,flush():刷新流,将流中的数据刷新到目的地中,流还存在。

5,close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。

public class IoTest2_Writer {

    public static void main(String[] args) throws Exception {
String path = "c:/ab.txt"; writeToFile(path);
} /**
* 写指定数据到指定文件中
*
*/
public static void writeToFile(String path) throws Exception {
Writer writer = new FileWriter(path);
writer.write('中');
writer.write("世界".toCharArray());
writer.write("中国"); writer.close();
}
}

2:追加文件:

  默认的FileWriter方法新值会覆盖旧值,想要实现追加功能需要

  使用如下构造函数创建输出流 append值为true即可。

  FileWriter(String fileName, boolean append)

  FileWriter(File file, boolean append)

3:flush方法

如果使用字符输出流,没有调用close方法,会发生什么?

private static void writeFileByWriter(File file) throws IOException {
FileWriter fw = new FileWriter(file);
fw.write('新');
fw.flush();
fw.write("中国".toCharArray());
fw.write("世界你好!!!".toCharArray());
fw.write("明天");
// 关闭流资源
//fw.close();
}

程序执行完毕打开文件,发现没有内容写入.原来需要使用flush方法. 刷新该流的缓冲。

为什么只要指定close方法就不用再flush方法,因为close也调用了flush方法.

字符流拷贝文件

一个文本文件中有中文有英文字母,有数字。想要把这个文件拷贝到别的目录中。

我们可以使用字节流进行拷贝,使用字符流呢?肯定也是可以的。

字符流拷贝文件实现1

public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt"; copyFile(path1, path2);
} /**
* 使用字符流拷贝文件
*/
public static void copyFile(String path1, String path2) throws Exception {
Reader reader = new FileReader(path1);
Writer writer = new FileWriter(path2); int ch = -1;
while ((ch = reader.read()) != -1) {
writer.write(ch);
} reader.close();
writer.close();
}

但是这个一次读一个字符就写一个字符,效率不高。把读到的字符放到字符数组中,再一次性的写出。

字符流拷贝文件实现2

public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt";
copyFile(path1, path2);
} public static void copyFile3(String path1, String path2) throws Exception {
Reader reader = new FileReader(path1);
Writer writer = new FileWriter(path2); int ch = -1;
char [] arr=new char[1024];
while ((ch = reader.read(arr)) != -1) {
writer.write(arr,0,ch);
} reader.close();
writer.close();
}

字节流可以拷贝视频和音频等文件,那么字符流可以拷贝这些吗?

  经过验证拷贝图片是不行的。发现丢失了信息,为什么呢?

计算机中的所有信息都是以二进制形式进行的存储(1010)图片中的也都是二进制

在读取文件的时候字符流自动对这些二进制按照码表进行了编码处理,但是图片本来就是二进制文件,不需要进行编码。有一些巧合在码表中有对应,就可以处理,并不是所有的二进制都可以找到对应的。信息就会丢失。所以字符流只能拷贝以字符为单位的文本文件

(以ASCII码为例是127个,并不是所有的二进制都可以找到对应的ASCII,有些对不上的,就会丢失信息。)

字符流的异常处理

public static void main(String[] args) throws Exception {
String path1 = "c:/a.txt";
String path2 = "c:/b.txt"; copyFile2(path1, path2);
} /**
* 使用字符流拷贝文件,有完善的异常处理
*/
public static void copyFile2(String path1, String path2) {
Reader reader = null;
Writer writer = null;
try {
// 打开流
reader = new FileReader(path1);
writer = new FileWriter(path2);
// 进行拷贝
int ch = -1;
while ((ch = reader.read()) != -1) {
writer.write(ch);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 关闭流,注意一定要能执行到close()方法,所以都要放到finally代码块中
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

字符流的缓冲区

  查看Reader 发现Reader,操作的是字符,我们就不需要进行编码解码操作,由字符流读到二进制,自动进行解码得到字符,写入字符自动编码成二进制.

Reader有一个子类BufferedReader。子类继承父类显然子类可以重写父类的方法,也可以增加自己的新方法。例如一次读一行就是常用的操作.那么BufferedReader 类就提供了这个方法,可以查看readLine()方法具备 一次读取一个文本行的功能。很显然,该子类可以对功能进行增强。

体验BufferedReader

public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
} private static void readFile(String path) throws IOException {
Reader read = new FileReader(path); BufferedReader br = new BufferedReader(read); String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
} }
}

注意:

在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,所以在建立缓冲区对象时,要先有流对象存在.

缓冲区的出现提高了对流的操作效率。原理:其实就是将数组进行封装。

使用字符流缓冲区拷贝文本文件.

public class Demo7 {
public static void main(String[] args) throws IOException {
// 关联源文件
File srcFile = new File("c:\\linux大纲.txt");
// 关联目标文件
File destFile = new File("d:\\linux大纲.txt");
// 实现拷贝
copyFile(srcFile, destFile); } private static void copyFile(File srcFile, File destFile)
throws IOException {
// 创建字符输入流
FileReader fr = new FileReader(srcFile);
// 创建字符输出流
FileWriter fw = new FileWriter(destFile); // 字符输入流的缓冲流
BufferedReader br = new BufferedReader(fr);
// 字符输出流的缓冲流
BufferedWriter bw = new BufferedWriter(fw); String line = null;
// 一次读取一行
while ((line = br.readLine()) != null) {
// 一次写出一行.
bw.write(line);
// 刷新缓冲
bw.flush();
// 进行换行,由于readLine方法默认没有换行.需要手动换行
bw.newLine();
}
// 关闭流
br.close();
bw.close();
}
}

装饰器模式

需求:想要在读取的文件的每一行添加行号。

public class IoTest7_BufferedReader {

    public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
} private static void readFile(String path) throws IOException {
Reader read = new FileReader(path); BufferedReader br = new BufferedReader(read);
int count = 0;
String line = null;
while ((line = br.readLine()) != null) {
count++;
System.out.println(count+":"+line);
} }
}

很容易的就可以实现。如果每次使用BufferedReader 输出时都需要显示行号呢? 每次都加? 很显然,我们的BufferedReader继承了Reader 对父类进行了功能的增强,那么我们也可以继承BufferedReader 重写该类的readLine方法,进行功能的增强.

public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
} private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader br = new MyBufferedReader(read);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
} }
} class MyBufferedReader extends BufferedReader {
public MyBufferedReader(Reader read) {
super(read);
}
int count;
@Override
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
count++;
return count + ":" + line;
} else {
return null;
} }
}

需求:

要在输出的一行前加上引号

可以再定义一个BufferedReader的子类,继承BufferedReader增强功能.

public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
} private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader br = new MyQutoBufferedReader(read);
int count = 0;
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
count++;
}
}
} // quotation 引号
class MyQutoBufferedReader extends BufferedReader {
public MyQutoBufferedReader(Reader reader) {
super(reader);
}
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
return "\"" + line + "\"";
} else {
return null;
} }
}

既想要显示行号又想要显示引号

发现,就需要再定义子类,发现这样比较麻烦,代码臃肿.而且代码重复.

可以换一种方式.如下:

其实就是一个新类要对原有类进行功能增强.

1. 在增强类中维护一个被增强的父类引用变量

2. 在增强类的构造函数中初始化1中的变量

3. 创建需要增强的方法,在刚方法中调用被被增强类的方法,并加以增强。

public class IoTest_BufferedReader {
public static void main(String[] args) throws IOException {
readFile("c:\\a.txt");
} private static void readFile(String path) throws IOException {
Reader read = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(read);
BufferedReader br = new MyQutoBufferedReader2(bufferedReader);
br = new MyLineBufferedReader2(br);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
} // quotation 引号
class MyQutoBufferedReader2 extends BufferedReader {
private BufferedReader bufferedReader;
public MyQutoBufferedReader2(BufferedReader bufferedReader) {
super(bufferedReader);
this.bufferedReader = bufferedReader;
}
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
return "\"" + line + "\"";
} else {
return null;
}
}
} class MyLineBufferedReader2 extends BufferedReader {
private BufferedReader bufferedReader;
public MyLineBufferedReader2(BufferedReader bufferedReader) {
super(bufferedReader);
this.bufferedReader = bufferedReader;
}
int count;
@Override
public String readLine() throws IOException {
String line = super.readLine();
if (line != null) {
count++;
return count + ":" + line;
} else {
return null;
}
}
}

800x600

Normal
0

7.8 磅
0
2

false
false
false

EN-US
ZH-CN
X-NONE

MicrosoftInternetExplorer4

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman",serif;}

这就是装饰器模式

装饰器模式:

使用分层对象来动态透明的向单个对象中添加责任(功能)。

装饰器指定包装在最初的对象周围的所有对象都具有相同的基本接口。

某些对象是可装饰的,可以通过将其他类包装在这个可装饰对象的四周,来将功能分层。

装饰器必须具有和他所装饰的对象相同的接口。

JavaIO中的应用:

Java I/O类库需要多种不同的功能组合,所以使用了装饰器模式。

FilterXxx类是JavaIO提供的装饰器基类,即我们要想实现一个新的装饰器,就要继承这些类。

装饰器与继承:

问题:

修饰模式做的增强功能按照继承的特点也是可以实现的,为什么还要提出修饰设计模式呢?

继承实现的增强类和修饰模式实现的增强类有何区别?

继承实现的增强类:

优点:代码结构清晰,而且实现简单

缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。

修饰模式实现的增强类:

优点:内部可以通过多态技术对多个需要增强的类进行增强

缺点:需要内部通过多态技术维护需要增强的类的实例。进而使得代码稍微复杂。

 

Normal
0

7.8 磅
0
2

false
false
false

EN-US
ZH-CN
X-NONE

MicrosoftInternetExplorer4

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman",serif;}
table.MsoTableGrid
{mso-style-name:网格型;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-unhide:no;
border:solid windowtext 1.0pt;
mso-border-alt:solid windowtext .5pt;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-border-insideh:.5pt solid windowtext;
mso-border-insidev:.5pt solid windowtext;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.0pt;
font-family:"Times New Roman",serif;}

java IO之 字符流 (字符流 = 字节流 + 编码表) 装饰器模式的更多相关文章

  1. Java IO流以及装饰器模式在其上的运用

    流概述 Java中,流是一种有序的字节序列,可以有任意的长度.从应用流向目的地称为输出流,从目的地流向应用称为输入流. Java的流族谱 Java的 java.io 包中囊括了整个流的家族,输出流和输 ...

  2. java进阶系列之装饰器模式

    1.介绍 装饰器模式顾名思义就是装饰某个对象的,是一种结构型模式.装饰器模式允许向一个现有对象添加新的功能,同时不改变其结构,用户可以随意的扩展原有的对象.它是作为现有的类的一个包装.装饰器模式一方面 ...

  3. Java设计模式12:装饰器模式

    装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...

  4. Java IO(Properties/对象序列化/打印流/commons-io)

    Java IO(Properties/对象序列化/打印流/commons-io) Properties Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载. ...

  5. Java设计模式--装饰器模式到Java IO 流

    装饰器模式 抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象. 具体构件角色:定义准备接受附加责任的对象. 抽象装饰角色:持有一个构件对象的实例,并对应一个与抽象构件接口一致的接口. 具体 ...

  6. 十:装饰器模式(io流)

    定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.                  这一个解释,引自百度百科,我们 ...

  7. 装饰器模式(IO流案例)

    装饰器模式,也成为包装模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能.其结构图如下: Component为统一接口,也是装饰类和被装饰类的基本类型. ConcreteCompone ...

  8. Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题

    PrintWriter打印流 Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便 同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法 ...

  9. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

随机推荐

  1. Microsoft Azure IoTHub Serials 1 - 使用Android设备与Azure IoTHub进行交互

    Azure IoTHub的目标是为物联网的应用场景提供方便的设备接入,完成消息的发送和接收(C2D和D2C).经过持续不断的努力,目前Azure IoTHub已经支持多种操作系统设备的接入,包括And ...

  2. [原创]nagios搭建配置

    nagios搭建配置 一.环境 ubuntu 14.04系统 host1:172.17.0.2 serverhost2:172.17.0.3 client 二.安装 1.在两个主机上都执行一下命令: ...

  3. java 与操作系统进程同步问题(一)————互斥问题

    最近学校开设了操作系统原理课程,老师要求用任意语言去模拟进程的同步和互斥问题. 在尝试的写了之后,发现这个问题非常有意思,故想记录在博客中,作为自己的学习轨迹. 个人还是比较喜欢用Java语言,所以采 ...

  4. UX2内核浏览加速技术纲要

    UX2内核是本人负责主要开发的浏览服务项目,其主要目的是为开发者提供一个简单好用.轻便的网络浏览服务.UX2内核的安卓端是基于WebView进行深度优化的,同时欢迎大家使用这个内核用于app页面或浏览 ...

  5. 利用nodeJs来安装less以及编译less文件为css文件

    NodeJs 使用nodejs安装less以及编译less文件为css文件 首先下载nodeJs的安装包,按照步骤,安装nodejs. 链接:http://pan.baidu.com/s/1dEsqY ...

  6. 《物联网框架ServerSuperIO教程》-21.终端控制传感器或设备,形成回路控制。附:demo源代码

    21.1     概述 ServerSuperIO以前所做的工作逐步为形成回路控制或级联控制打下基础,例如:服务连接器和设备驱动连接器的开发与应用.总之,是通过多种形式下发命令控制设备(驱动)或传感器 ...

  7. iOS开发之资讯类App常用分类控件的封装与实现(CollectionView+Swift3.0+)

    今天博客中,我们就来实现一下一些常用资讯类App中常用的分类选择的控件的封装.本篇博客中没有使用到什么新的技术点,如果非得说用到了什么新的技术点的话,那么勉强的说,用到了一些iOS9以后UIColle ...

  8. JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

    JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...

  9. Python中的枚举

    在Python中想要实现枚举功能的方式比较多,可以通过字典这一数据结构,利用键与值的对应关系,可以实现枚举的功能. my_Enum={ 'red':1, 'yellow':2, 'blue':3 } ...

  10. 没有main方法真的不能执行代码了吗?

    今天看北大慕课遇到一段代码,于是下载下来跑了一下,奇葩的是,没有main方法既没报错,还出了结果. 下面贴出代码: class InitialTest { public static void mai ...