您的位置:首页 > 职场人生

黑马程序员_Java基础_IO流(四)_21

2014-02-10 00:41 363 查看
------- android培训java培训、期待与您交流!----------

导读:对象的序列化,管道流,RandomAccessFile,操作基本数据类型的流对象, ByteArrayStream,字符流的字符编码,编码解码,字符编码-联通,练习

1、IO流(对象的序列化)

IO包中的其他类:操作对象,ObjectInputStream与ObjectOutputStream,它们是能对“对象”进行操作的字节流。流是用来操作数据的,可是数据被封装到了堆内存中了。因为对象都存储在堆内存中,当程序运行完后,在堆内存中的垃圾就会被垃圾回收机制给回收了。运用些流,可以将堆内存中的对象存放到硬盘上,这些数据也会随着对象存储到了硬盘上(对象的持久化存储,或者叫对象的序列化)。如果想拿数据来用的话,只用把文件中的对象读一次就可以了。
被操作的对象需要实现Serializable (标记接口); public interfaceSerializable类通过实现 java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。(在这个接口中没有方法,没有方法的接口称之为标记接口)
对象想要序列化,类必须实现这个Serializable接口,这叫做标记,你具备这个资格才让你序列化。原理是,给类加一个UID标识,这个UID是给编译器使用的。如果类改变的话,会生成一个新的ID号(根据类中不同的成员算这个ID)。生成的文件是对象中的数据,用记事本打开,记事本要查GBK的表,生成的文件没有希望你能看得懂。
构造方法:

Ø ObjectOutputStream(OutputStream out):创建写入指定 OutputStream 的ObjectOutputStream。(接收一个流进来)

ObjectOutputStream,java.io中的类publicclass ObjectOutputStreamextends OutputStream,ObjectOutputStream将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用ObjectInputStream 读取(重构)对象。它继承自OutputStream,它中有OutputStream中的相关的方法。
方法:

Ø write();

Ø writeInt(int val)等:可以操作基本数据类型。writeInt(int val),可以将四个字节全部写出去。区别于write(int val)方法。

Ø write():只将最低的8位写出去。

Ø void writeObject(Object obj):将指定的对象写入 ObjectOutputStream。(方法可以接收一个对象进来)

我对某些已经定义好的对象中的数值进行了持久化的存储,你不需要再住里面传值了,你也不知道要往里面传什么。把对象读出来,拿出来用就可以了(不需要new,不需要数值的传递了)。
import java.io.*;

class ObjectStreamDemo

{

publicstatic void main(String[] args) throws Exception

{

//writeObj();

readObj();

}

public static void readObj()throws Exception

{

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));

Personp = (Person)ois.readObject();

System.out.println(p);

ois.close();

}

public static void writeObj()throws IOException

{

ObjectOutputStream oos =

newObjectOutputStream(new FileOutputStream("obj.txt"));

    //一般不存成obj.txt,因为txt可以打开,可是打开也看不懂,可以存成person.object

oos.writeObject(newPerson("lisi0",399,"kr")); //这里的kr是不能够被序列化到硬盘上,因为kr传进去之后是静态的,不是在堆内存中的,不被序列化。这里可以写多个oos.writeObject(new Person("",""));存入多个对象,readObject()一次返回一个对象,readObject()第二次,返回第二个对象。

oos.close();

}

}

import java.io.*;

class Person implements Serializable

{

  //UID给类定义一个序列化的标识,其实就是了为序列化的方便。在生成obj.txt后,在name前加上一个private的时候就会生成一个新的UID。这个时候就不能和原来的obj.txt文件了,不让你读了。为了还可以读原来的文件,可以在类中自己定义一个UID不让java自动生成。

publicstatic final long serialVersionUID = 42L;//自己定义一相UID新的类,还可以用原来的,序列化的对象。

privateString name;

transientint age; //如果非静态的成员也不想让它序列化的话,可以加上transient,其值在堆内存中存在,而不在文本文件中存在。

staticString country = "cn";

Person(Stringname,int age,String country)

{

this.name= name;

this.age= age;

this.country= country;

}

public String toString()

{

return name+":"+age+":"+country;

}

}

ObjectOutputStream和ObjectInputStream必须成对的出现。

2、IO流(管道流)

IO包中的其他类:

管道流(PipedInputStream和PipedOutputStream),输入输出可以直接进行连接,通过结合线程使用。

读写流,中间有一个中转站(数组)。而管道流,他们可以接上。从这个管子里面写,从那个管子中就可以读到,这两根管子可以拧到一块去。
public class PipedInputStreamextendsInputStream管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。(涉及了多线程技术的IO流对象。)
集合当中涉及到IO流的是Properties,在IO流中涉及到多线程的是管道流。
PipedInputStream(PipedOutputStream src):创建 PipedInputStream,使其连接到管道输出流src。
PipedInputStream():创建尚未连接的 PipedInputStream。
要么非空的构造函数传入输入管道流,要么空的构造函数用方法,void connect(PipedOutputStream src):使此管道输入流连接到管道输出流 src。
import java.io.*;

class Read implements Runnable

{

private PipedInputStream in;

Read(PipedInputStreamin)

{

this.in= in;

}

publicvoid run()

{

try

{

byte[] buf = new byte[1024];

System.out.println("读取前。。没有数据阻塞");

intlen = in.read(buf);

System.out.println("读到数据。。阻塞结束");

Strings= new String(buf,0,len);

System.out.println(s);

in.close();

}

catch(IOException e)

{

throw new RuntimeException("管道读取流失败");

}

}

}

class Write implements Runnable

{

privatePipedOutputStream out;

Write(PipedOutputStreamout)

{

this.out= out;

}

public void run()

{

try

{

System.out.println("开始写入数据,等待6秒后。");

Thread.sleep(6000);

out.write("pipedlai la".getBytes());

out.close();

}

catch(Exception e)

{

throw new RuntimeException("管道输出流失败");

}

}

}

class PipedStreamDemo

{

publicstatic void main(String[] args) throws IOException

{

PipedInputStreamin = new PipedInputStream();

PipedOutputStreamout = new PipedOutputStream();

in.connect(out);

Readr = new Read(in);

Writew = new Write(out);

newThread(r).start();

newThread(w).start();

}

}

两个线程,谁先抢到资源,不重要。因为有一个阻塞式的方法read(),我没有写你就得等,等我写完了你再执行。

3、IO流(RandomAccessFile)

RandomAccessFile,随机访问文件,自身具备读写的方法。通过skipBytes(int x),seek(int x)来达到随机访问。(它的结尾处没有父类名,是自动一派的工具类,直接继承自Object,publicclass RandomAccessFileextends Object)此类的实例支持对随机访问文件的读取和写入(即能读又能写)。
可以实现文件的分段写入。将数据分成段之后,可以让一个线程负责一段(下载软件的原理)。一般的流是从前往后写,它们写出来的文件就不是连续的文件了。
RandomAccessFile该类不是算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员。因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
构造函数:

Ø RandomAccessFile(File file, String mode)

Ø RandomAccessFile(String name, String mode)

mode 参数指定用以打开文件的访问模式

局限性:

通过构造函数可以看出,该类只能操作文件。(设备上只有硬盘,没有别的)。而且操作文件还有模式:只读r,读写rw等。

如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。

如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

方法:

Ø int read(byte[] b)

Ø int readInt():读基本数据类型等。

Ø String readLine():读一行。

Ø void seek(long pos):指向位置。

Ø void write(byte[] b)

Ø void writeInt(int v)

Ø int skipBytes(int n):跳过多少个字节。

import java.io.*;

class RandomAccessFileDemo

{

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

{

//writeFile_2();

//readFile();

//System.out.println(Integer.toBinaryString(258));

}

public static void readFile()throws IOException

{

RandomAccessFile raf = new RandomAccessFile("ran.txt","r");

//调整对象中指针。(前提:要保证数据是有规律的,不然取起来就费劲了,为使数据有规律,可以在存的时候补位)

//raf.seek(8*1); //取第二个人。取第一个人是8*0。seek()是前后都能指,想指哪指哪。

//跳过指定的字节数

raf.skipBytes(8); //跳过可以往下跳,但是不能往回跳。

byte[]buf = new byte[4];

raf.read(buf);

Stringname = new String(buf);

intage = raf.readInt();

System.out.println("name="+name);

System.out.println("age="+age);

raf.close();

}

public static void writeFile_2()throws IOException

{

RandomAccessFileraf = new RandomAccessFile("ran.txt","rw");

    //一new对象的话,不另创建文件,而是直接在里面写数据。而输出流一new对象就要覆盖文件。

raf.seek(8*3); //如果这里是8*0的话,对于李四这个位置上的数据修改为周七。

raf.write("周七".getBytes()); 

//随机的可以往里面读写。第一个位置是,李四。第二个位置是王五。第三个位置不知道是什么,直接在第四个位置里写入周七。

raf.writeInt(103);

raf.close();

}

publicstatic void writeFile()throws IOException

{

RandomAccessFileraf = new RandomAccessFile("ran.txt","rw");

raf.write("李四".getBytes());

raf.writeInt(97);

raf.write("王五".getBytes());

raf.writeInt(99); //直接写基本数据类型。

raf.close();

}

}

4、IO流(操作基本数据类型的流对象)

DataInputStream与DataOutputStream可以用于操作基本数据类型的数据的流对象。(如果只是为了操作基本数据类型的话,用这个是非常方便的。)
构造方法:

DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。

void writeUTF(String str):以与机器无关方式使用 UTF-8 修改版(null 字节 '\u0000' 是用 2-byte 格式而不是 1-byte 格式编码的)编码将一个字符串写入基础输出流。(用这种方式写入的字符串,只能用它对应的方式写出来,用转换流读不出来)
import java.io.*;

class DataStreamDemo

{

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

{

//writeData();

//readData();

//writeUTFDemo();

// OutputStreamWriterosw = new OutputStreamWriter(newFileOutputStream("gbk.txt"),"gbk");

// osw.write("你好"); //这里占了4个字节,UTF-8写入占6个字节,修改版的UTF-8占了8个字节。只能用相对应的方法读出来,而不能用UTF-8读出来

// osw.close();

// readUTFDemo();

}

public static void readUTFDemo()throws IOException

{

DataInputStreamdis = new DataInputStream(new FileInputStream("utf.txt"));

Strings = dis.readUTF(); //只能用这个读出来。

System.out.println(s);

dis.close();

}

public static void writeUTFDemo()throws IOException

{

DataOutputStreamdos = new DataOutputStream(new FileOutputStream("utfdate.txt"));

dos.writeUTF("你好");

dos.close();

}

public static void readData()throws IOException

{

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

int num = dis.readInt(); //写的时候是先写的整数,读的时候也要先读整数。要是以前的话,要先存入4个字节,再将4个字节转化为字符串,再将字符串强转成一个整数。

boolean b = dis.readBoolean();

double d = dis.readDouble();

System.out.println("num="+num);

System.out.println("b="+b);

System.out.println("d="+d);

dis.close();

}

public static void writeData()throws IOException

{

DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

dos.writeInt(234);

dos.writeBoolean(true);

dos.writeDouble(9887.543);

dos.close();

ObjectOutputStreamoos = null;

oos.writeObject(newO());

}

}

5、IO流(ByteArrayStream)

操作字节数组

ByteArrayInputStream与ByteArrayOutputStream,是能直接操作字节数组中字节数据的流对象。

public class ByteArrayInputStream extends InputStream,ByteArrayInputStream包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。关闭ByteArrayInputStream 无效(没有和文件打交道,就没有调用底层资源,关闭是没有什么效果的,关不关都一样)。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
ByteArrayInputStream(byte[] buf)
方法摘要

Ø int available():返回可从此输入流读取(或跳过)的剩余字节数。

Ø int read():从此输入流中读取下一个数据字节。

Ø void reset():将缓冲区的位置重置为标记位置。

Ø long skip(long n):从此输入流中跳过 n 个输入字节。

public class ByteArrayOutputStreamextendsOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString()
获取数据。 关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
ByteArrayOutputStream():创建一个新的 byte 数组输出流。

ByteArrayOutputStream(int size):size用于指定大小的缓冲区容量。

对象中封装的就是一个可变长度以字节数组,这个数组就是目的。

int size():返回缓冲区的当前大小。

byte[] toByteArray():创建一个新分配的 byte 数组。

String toString()

void writeTo(OutputStream out):写到目的中去,这个目的可以是一个字节输出流。

用于操作字节数组的流对象。

Ø ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。

Ø ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。这就是数据目的地。

因为这两个流对象都操作的数组,并没有使用系统资源。所以,不用进行close关闭。

在流操作规律讲解时:

源设备,

键盘 System.in,硬盘FileStream,内存 ArrayStream。

目的设备:

控制台 System.out,硬盘FileStream,内存 ArrayStream。

对于数组进行封装,不仅是为了代码的封装性、代码的复用性,更重要的是:用流的读写思想来操作数组。对数组的操作无非有两个,一个是读,一个是写。
import java.io.*;

class ByteArrayStream

{

public static void main(String[] args)

{

//数据源。

ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());

//数据目的

ByteArrayOutputStream bos = new ByteArrayOutputStream();

intby = 0;

while((by=bis.read())!=-1) //不用判断数组大小,更方便了。读操作

{

bos.write(by); //写操作

}

System.out.println(bos.size()); //缓冲区的大小

System.out.println(bos.toString());

// bos.writeTo(newFileOutputStream("a.txt")); //只有这一个方法涉及到异常了。

}

}

下面两个和上面的ByteArrayInputStream和ByteArrayOutputStream都是以内存为源和目的的操作:

Ø 操作字符数组:CharArrayReader与CharArrayWrite

Ø 操作字符串:StringReader 与StringWriter

6、IO流(字符流的字符编码)

字符编码

Ø 字符流的出现为了方便操作字符。

Ø 更重要是的加入了编码转换。

Ø 通过子类转换流来完成。(下面两个是加入了编码表的流对象,还有两个是PrintStream和PrintWriter,这两个只能去打印不能去读取)

Ø InputStreamReader

Ø OutputStreamWriter

Ø 在两个对象进行构造的时候可以加入字符集。

编码表的由来

Ø 计算机只能识别二进制数据,早期由来是电信号。

Ø 为了方便应用计算机,让它可以识别各个国家的文字。

Ø 就将各个国家的文字用数字来表示,并一一对应,形成一张表。

Ø 这就是编码表。

常见的编码表

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

Ø ISO8859-1:拉丁码表。欧洲码表(用一个字节的8位表示)

Ø GB2312:中国的中文编码表。(中国的码表兼容ASCII码表,两个字节的高位都用1来表示,带符号六七千个字)

Ø GBK:中国的中文编码表升级,融合了更多的中文文字符号。(扩容了,两万多,56个民族的文字都加进来就好了。GB18030)

Ø Unicode:国际标准码,融合了多种文字。(所有文字都用两个字节来表示,Java语言(char类型)使用的就是unicode。但一个字节能装下的文字,两个字节比较浪费,)

Ø UTF-8:最多用三个字节来表示一个字符。(一个能装下的用一个字节装,二个字节不够的用三个字节装。在每一个字节的开头都有一个标识头,加了之后,就能很容易的区别出什么样的编码才是UTF-8的编码)

可是GBK能够识别中文,UTF-8也能识别中文,但是同样的码却对应了不同的文字,这就涉及到了编码的转换问题。有些人用的是UTF-8的编码,有些人用的是GBK的编码,两个码表都能识别中文,可以却出现了乱码,这是因为解析出现了问题。
如果下次再出现乱码,你把你好仍进去,如果出现两个??,说明是用GBK编的码,用UTF-8解的码。如果你好仍进去,出现了浣犲,则是用UTF-8编的码,用GBK解的。
import java.io.*;

class EncodeStream

{

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

{

//writeText();

readText();

}

public static void readText()throws IOException

{

InputStreamReader isr = new InputStreamReader(newFileInputStream("utf.txt"),"gbk");

char[] buf = new char[10];

int len = isr.read(buf);

String str = new String(buf,0,len);

System.out.println(str);

isr.close();

}

publicstatic void writeText()throws IOException

{

OutputStreamWriterosw = new OutputStreamWriter(newFileOutputStream("utf.txt"),"UTF-8");

osw.write("你好");

osw.close();

}

}

7、编码解码

编码解码就是对于数据进行转换。把看懂得,变成看不懂的,把看懂的变成看不懂的。
编码:字符串变成字节数组。

解码:字节数组变成字符串。

String-->byte[]; str.getBytes(charsetName);

byte[] -->String: newString(byte[],charsetName);

import java.util.*;

class EncodeDemo

{

public static void main(String[] args)throws Exception

{

Strings = "哈哈";

byte[] b1 = s.getBytes("GBK");

System.out.println(Arrays.toString(b1));

Strings1 = new String(b1,"utf-8");

System.out.println("s1="+s1);

//若对s1进行iso8859-1解码再编码,就能正确的读出来输出正确结果,因为iso8859-1不识别中文。

byte[] b2 = s1.getBytes("utf-8"); //如果这里用utf-8,因为UTF-8和GBK都识别中文,在这里编译将???编码的时候会编码错误,解码的时候也更不会正确。

System.out.println(Arrays.toString(b2));

String s2 = new String(b2,"gbk");

System.out.println("s2="+s2);

}

}

为什么要这样去写呢?tomcat用的默认编码是ISO8859-1。玩服务器的时候真的会出现乱码的(????)。这个时候就要将?在服务器端编译一次再解一次。如果get的话,就必须要这么做,如果是post提交的话,你可以通过服务器中一个对象的函数叫做:setCharacterEncoding()设置字符编码,它自动帮你转换。
在这个程序中如果s为“你好”,输出s2=锟斤拷锟?,如果s为“哈哈”,输出s2=锟斤拷锟斤拷,s1和s2很像。这是因为在UTF-8中它也支持连续三个负数的文字,先拿了两个或者三个去查,查了之后,没有查着符合UTF-8规则的数据,它把字符编码表中除了对应数据区以外的部分叫做未知字符区域,它到这里面去查去了。查了之后,就查了一堆相似的字符返回来了。

08、字符编码-联通

UTF-8中可以读两个字符,也可能读三个字符,UTF-8的码表,它都对于字节都加了一个标识头信息,它根据自己的标识头就能知道,我一次是读一个字节呢,还是一次读两个字节呢,还是一次读三个字节呢。一个字节开始位是0。两个字节的话,第一个字节,开始位是110,第二个字节开始位是10。三个字节表示的话,第一个字节开始位是1110,第二个字节开始位是10,第三个字节开始位是10。用这来判断往后面读到底是读一个还是读两个还是读三个。
class EncodeDemo2

{

public static void main(String[] args) throws Exception

{

Strings = "联通";

byte[] by = s.getBytes("gbk");

for(byteb : by)

{

System.out.println(Integer.toBinaryString(b&255));

}

System.out.println("HelloWorld!");

}

}

联通这两个字的二进制形式为:

11000001

10101010

11001101

10101000

正好符合UTF-8的形式,所以用记事本打开的时候,记事本查的是UTF-8的编码而不是GBK的编码。所以出现了乱码。可在在记事本的前面加上一个汉字,这样就用GBK来解,不用UTF-8来解就正确了。

9、练习

有五个学生,每个学生有3门课的成绩,

从键盘输入以上数据(包括姓名,三门课成绩),

输入的格式:如:zhagnsan,30,40,60计算出总成绩,

并把学生的信息和计算出的总分数高低顺序存放在磁盘文件"stud.txt"中。

1,描述学生对象。

2,定义一个可操作学生对象的工具类。

思想:

1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。

2,因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。

所以可以使用TreeSet。

3,将集合的信息写入到一个文件中。

*/

import java.io.*;

import java.util.*;

class Student implements Comparable<Student>

{

private String name;

private int ma,cn,en;

private int sum;

Student(Stringname,int ma,int cn,int en)

{

this.name= name;

this.ma= ma;

this.cn= cn;

this.en= en;

sum= ma + cn + en;

}

public int compareTo(Student s)

{

intnum = new Integer(this.sum).compareTo(new Integer(s.sum));

if(num==0)

returnthis.name.compareTo(s.name);

return num;

}

public String getName()

{

return name;

}

public int getSum()

{

return sum;

}

public int hashCode()

{

return name.hashCode()+sum*78;

}

public boolean equals(Object obj)

{

if(!(objinstanceof Student))

thrownew ClassCastException("类型不匹配");

Students = (Student)obj;

return this.name.equals(s.name) && this.sum==s.sum;

}

publicString toString()

{

return "student["+name+", "+ma+", "+cn+","+en+"]";

}

}

class Student InfoTool

{

//对外提供两个方法,一个是没有比较器的,另一个是有比较器的。没有比较器的和有比较器的代码大致相同。只用传入null即可,在有比较器中做一下判断。

public static Set<Student> getStudents() throws IOException

{

return getStudents(null);

}

public static Set<Student> getStudents(Comparator<Student> cmp)throws IOException

{

BufferedReaderbu fr =

newBufferedReader(new InputStreamReader(System.in));

Stringline = null;

Set<Student>stus = null;

if(cmp==null) //做一下判断。

stus= new TreeSet<Student>();

else

stus= new TreeSet<Student>(cmp);

while((line=bufr.readLine())!=null)

{

if("over".equals(line))

break;

String[]info = line.split(",");

Student stu = new Student(info[0],Integer.parseInt(info[1]),

Integer.parseInt(info[2]),

Integer.parseInt(info[3]));

stus.add(stu); //二叉树在这里已经排了。

}

bufr.close();

return stus;

}

public static void write2File(Set<Student> stus) throws IOException

{

BufferedWriterbu fw = new BufferedWriter(new FileWriter("stuinfo.txt"));

for(Studentstu : stus)

{

bufw.write(stu.toString()+"\t");

bufw.write(stu.getSum()+"");

bufw.newLine();

bufw.flush(); //带缓冲区,一定要flush()

}

bufw.close();

}

}

class StudentInfoTest

{

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

{

Comparator<Student> cmp = Collections.reverseOrder();

//定义一个自己的比较器,将成绩反转,按从大到小排列,否则默认的是从小到大。

Set<Student> stus = StudentInfoTool.getStudents(cmp);

StudentInfoTool.write2File(stus);

}

}

/*

猜数字游戏:

1,产生随机数。

2,获取键盘录入。

3,将录入数据变成数字,和随机数比较。

给出提示信息。

4,重复这个过程,如果猜中,程序就结束。

注意:对于输入1~100以外的数字,,以及非数字要给出提示。

*/

import java.io.*;

import java.util.*;

class GuessNumber

{

private int ranNum;

GuessNumber()

{

Randomr = new Random();

ranNum= r.nextInt(100)+1;//(int)Math.random()*100+1;

}

public void play()

{

System.out.println("游戏开始:输入1~100之间的数字:");

boolean b = false;

while(!b)

{

try

{

int num = getNum();

if(num>=1&& num<=100)

b= isLuck(num);

else

System.out.println("数值超出范围");

}

catch(IOException e)

{

throw new RuntimeException("录入数据失败");

}

catch(NumberFormatExceptione)

{

System.out.println("输入了非法数据");

}

}

}

//获取键盘的数字

privateint getNum()throws IOException,NumberFormatException

{

BufferedReaderbu fr = new BufferedReader(new InputStreamReader(System.in));

int num = Integer.parseInt(bufr.readLine());

return num;

}

//和随机数比较

private boolean isLuck(int num)

{

booleanb = false;

if(num>ranNum)

System.out.println("大了,继续");

elseif(num<ranNum)

System.out.println("小了,继续");

else

{

System.out.println("中了,恭喜");

b= true;

}

returnb;

}

}

class GuessNumberDemo

{

public static void main(String[] args)

{

new GuessNumber().play();

}

}

------- android培训java培训、期待与您交流!----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: