码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA笔记(十三)

时间:2016-05-14 23:07:50      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

  1.  

package cn.itcast.dao.impl;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import cn.itcast.dao.UserDao;

import cn.itcast.pojo.User;

/**

 * 这是用户操作的具体实现类(IO版)

 *

 * @author 风清扬

 * @version V1.1

 */

public class UserDaoImpl implements UserDao {

       // 为了保证文件一加载就创建

       private static File file = new File("user.txt");

static {

              try {

                     file.createNewFile();

              } catch (IOException e) {

                     System.out.println("创建文件失败");

                     // e.printStackTrace();

              }

       }

@Override

       public boolean isLogin(String username, String password) {

              boolean flag = false;

BufferedReader br = null;

              try {

                     // br = new BufferedReader(new FileReader("user.txt"));

                     br = new BufferedReader(new FileReader(file));

                     String line = null;

                     while ((line = br.readLine()) != null) {

                            // 用户名=密码

                            String[] datas = line.split("=");

                            if (datas[0].equals(username) && datas[1].equals(password)) {

                                   flag = true;

                                   break;

                            }

                     }

              } catch (FileNotFoundException e) {

                     System.out.println("用户登录找不到信息所在的文件");

                     // e.printStackTrace();

              } catch (IOException e) {

                     System.out.println("用户登录失败");

                     // e.printStackTrace();

              } finally {

                     if (br != null) {

                            try {

                                   br.close();

                            } catch (IOException e) {

                                   System.out.println("用户登录释放资源失败");

                                   // e.printStackTrace();

                            }

                     }

              }

return flag;

       }

@Override

       public void regist(User user) {

              /*

               * 为了让注册的数据能够有一定的规则,我就自己定义了一个规则: 用户名=密码

               */

              BufferedWriter bw = null;

              try {

                     // bw = new BufferedWriter(new FileWriter("user.txt"));

                     // bw = new BufferedWriter(new FileWriter(file));

                     // 为了保证数据是追加写入,必须加true

                     bw = new BufferedWriter(new FileWriter(file, true));

                     bw.write(user.getUsername() + "=" + user.getPassword());

                     bw.newLine();

                     bw.flush();

              } catch (IOException e) {

                     System.out.println("用户注册失败");

                     // e.printStackTrace();

              } finally {

                     if (bw != null) {

                            try {

                                   bw.close();

                            } catch (IOException e) {

                                   System.out.println("用户注册释放资源失败");

                                   // e.printStackTrace();

                            }

                     }

              }

       }

}

 

 

  1.   其他的流(了解),每种颜色代表一种大的流。

 操作基本数据类型

(操作基本数据的流)

DataInputStream

DataOutputStream

内存操作流

操作字节数组

ByteArrayInputStream

ByteArrayOutputStream

操作字符数组

CharArrayReader

CharArrayWrite

操作字符串

StringReader

StringWriter

内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。

2:以第一个举例即可

ByteArrayOutputStream baos = new ByteArrayOutputStream();

baos.write("helloworld".getBytes());

baos.close();

byte[] bys = baos.toByteArray();

ByteArrayInputStream bais = new ByteArrayInputStream(bys);

int by = 0;

while ((by = bais.read()) != -1) {

System.out.println((char) by);

}

baos.close();

bais.close();

最后的close()可以不写,通过看源码可以知道这里什么都没有做。

 打印流概述

:只有写,没有读。

字节流打印流

字符打印流

打印流特点

只能操作目的地,不能操作数据源。

可以操作任意类型的数据。

如果启动了自动刷新,能够自动刷新。

可以操作文件的流

打印流复制文本文件

 System类中的字段:in,out。(标准的输入输出流)

它们各代表了系统标准的输入和输出设备。

默认输入设备是键盘,输出设备是显示器。

System.in的类型是InputStream.

(字节流)System.out的类型是PrintStream(字符打印流)

是OutputStream的子类FilterOutputStream 的子类.

RandomAccessFile概述

RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。【该类的构造方法的第二个参数就是读写文件的模式,一共有四种,用得最多的是rw】utf对应汉字的是3个字节,想读取就可以读取那个位置,是通过设置指针位置来实现的。

SequenceInputStream概述

(合并流)SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

SequenceInputStream的构造方法

SequenceInputStream(InputStream s1, InputStream s2) 

SequenceInputStream(Enumeration<? extends InputStream> e)

把多个文件的内容写入到一个文本文件

合并流的一个构造可以合并两个文件,有一个构造可以合并多个文件,但是需要注意的是,该多个流的合并需要用到vector集合的方法,所以就得创建该集合。

  1.  打印流如果启动了自动刷新,对于某些方法就可以不用刷新和换行了。(比如println())。 该流的底层也高效。           
  2. 在jdk1.5之前,没有scanner这个类,为了使键盘输入数据就通过字符缓冲流包装标准输入流实现【BufferedReader br=new BufferedReader(new InputStream(System.in)).】
  3. 注意一点:字符流如果不能显示在控制台或者文件中,看看是否刷新缓冲区了。
  4. 序列化流: 

 序列化流

ObjectOutputStream

(写)反序列化流

ObjectInputStream

(读)序列化操作问题

为什么要实现序列化?

如何实现序列化?

序列化数据后,再次修改类文件,读取数据会出问题,如何解决呢?

使用transient关键字声明不需要序列化的成员变量

对象序列化是将对象状态转换为可保持或传输的过程。一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点。

对象反序列化,是指把这种二进制流数据还原成对象。

 

Properties概述

Properties作为Map集合的使用

,(但是不能有泛型)Properties的特殊功能

public Object setProperty(String key,String value)

【添加元素】public String getProperty(String key)

【获取元素】public Set<String> stringPropertyNames()

【获取所有键的集合】Properties和IO流的结合使用

public void load(Reader reader)

【把文件的数据读取到集合中】public void store(Writer writer,String comments)

【把集合中的数据存储到文件】注意这里的集合只能是Priperties.这个文件的数据也必须是键值对形式。该集合可以应用于单机游戏状态的存贮。

NIO其实就是新IO的意思。

JDK4出现NIO。新IO和传统的IO有相同的目的,都是用于进行输入输出的,但新IO使用了不同的方式来处理输入输出,采用内存映射文件的方式,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样的来访问文件了,这种方式效率比旧IO要高很多,但是目前好多地方我们看到的还是旧IO的引用,所以我们仍以旧IO为主,知道NIO即可。Buffer(缓冲),Channer(通道)

JDK7要了解的新IO类

Path:与平台无关的路径。

Paths:包含了返回Path的静态方法。

       public static Path get(URI uri):根据给定的URI来确定文件路径。

Files:操作文件的工具类。提供了大量的方法,简单了解如下方法

       public static long copy(Path source, OutputStream out) :复制文件

       public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options):

              把集合的数据写到文件。

//复制文件

Files.copy(Paths.get("Demo.java"), newFileOutputStream("Copy.Java"));

//把集合中的数据写到文件

List<String> list = new ArrayList<String>();

list.add("hello");

list.add("world");

list.add("java");

Files.write(Paths.get("list.txt"), list, Charset.forName("gbk"));

 

 

  1.  要想实现序列化和反序列化就必须实现serializable接口,该接口中没有任何方法,在java中,没有任何方法的接口称为标记接口。           
  2. 看到类实现了序列化接口的时候,要想解决黄色警告线的问题,就可以产生一个序列化id值,而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。               
  3.  打印流复制文件代码

    BufferedReader br = new BufferedReader(new FileReader("a.txt"));

              PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);

              String line = null;

              while((line=br.readLine())!=null) {

                     pw.println(line);

              }

              pw.close();

              br.close();      

  1. Jdk1.7新特性的代码【了解使用】

  package cn.itcast_09;

import java.io.IOException;

import java.nio.charset.Charset;

import java.nio.file.Files;

import java.nio.file.Paths;

import java.util.ArrayList;

/*

 * nio包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。

 * 有空的话了解下,有问题再问我。

 * JDK7的之后的nio:

 * Path:路径

 * Paths:有一个静态方法返回一个路径

 *               public static Path get(URI uri)

 * Files:提供了静态方法供我们使用

 *               public static long copy(Path source,OutputStream out):复制文件

 *               public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)

 */

public class NIODemo {

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

              // public static long copy(Path source,OutputStream out)

              // Files.copy(Paths.get("ByteArrayStreamDemo.java"), new

              // FileOutputStream(

              // "Copy.java"));

ArrayList<String> array = new ArrayList<String>();

              array.add("hello");

              array.add("world");

              array.add("java");

              Files.write(Paths.get("array.txt"), array, Charset.forName("GBK"));

       }

}

  1.  Properties的经典代码

    package cn.itcast_08;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.Reader;

import java.io.Writer;

import java.util.Properties;

/*

 * 这里的集合必须是Properties集合:

 * public void load(Reader reader):把文件中的数据读取到集合中

 * public void store(Writer writer,String comments):把集合中的数据存储到文件

 * 单机版游戏:

 *               进度保存和加载。

 *               三国群英传,三国志,仙剑奇侠传...

 *

 *               吕布=1

 *               方天画戟=1

 */

public class PropertiesDemo3 {

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

              // myLoad();

 

              myStore();

       }

private static void myStore() throws IOException {

              // 创建集合对象

              Properties prop = new Properties();

prop.setProperty("林青霞", "27");

              prop.setProperty("武鑫", "30");

              prop.setProperty("刘晓曲", "18");

              //public void store(Writer writer,String comments):把集合中的数据存储到文件

              Writer w = new FileWriter("name.txt");

              prop.store(w, "helloworld");

              w.close();

       }

private static void myLoad() throws IOException {

              Properties prop = new Properties();

// public void load(Reader reader):把文件中的数据读取到集合中

              // 注意:这个文件的数据必须是键值对形式

              Reader r = new FileReader("prop.txt");

              prop.load(r);

              r.close();

System.out.println("prop:" + prop);

       }

}         

  1.   游戏设置次数的代码

   package cn.itcast_08;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.Reader;

import java.io.Writer;

import java.util.Properties;

/*

 * 我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。

 */

public class PropertiesTest2 {

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

              // 读取某个地方的数据,如果次数不大于5,可以继续玩。否则就提示"游戏试玩已结束,请付费。"

              // 创建一个文件

              // File file = new File("count.txt");

              // if (!file.exists()) {

              // file.createNewFile();

              // }

// 把数据加载到集合中

              Properties prop = new Properties();

              Reader r = new FileReader("count.txt");

              prop.load(r);

              r.close();

// 我自己的程序,我当然知道里面的键是谁

              String value = prop.getProperty("count");

              int number = Integer.parseInt(value);

if (number > 5) {

                     System.out.println("游戏试玩已结束,请付费。");

                     System.exit(0);

              } else {

                     number++;

                     prop.setProperty("count", String.valueOf(number));

                     Writer w = new FileWriter("count.txt");

                     prop.store(w, null);

                     w.close();

GuessNumber.start();

              }

       }

}    

  1. 如果程序只有一条执行路径,那么该程序就是单线程程序,如果程序有多条【大于等于2】执行路径,那么该程序就是多线程程序。
  2. 进程就是正在运行的程序,多进程的意义就是提高cpu的使用率,在同一时间段同时运行,但是同一时间点是不可能的。
  3. 在同一个进程中又可以执行多个任务,而这每一个任务就可以看做是一个线程,多线程可以是进程拥有更大的几率抢到cpu资源,从而提高了程序的使用率。
  4. 我们不敢保证哪一个线程在某一时刻抢到资源,所以线程的执行是随机的。
  5. 并行(同一时间段)并发(同一时间点)
  6. Jvm的启动其实是多线程的,除了主线程之外,垃圾回收线程也会先启动,否则容易造成内存溢出,所以java虚拟机最低启动了两个线程。
  7. 实现多线程的2个方法【其实是3个】1.继承thread类,重写该类中的run()方法。2. 实现Runnable接口3.(了解)、使用ExecutorService、Callable、Future实现有返回结果的多线程
  8.  不是类中的所有代码都需要被(多)线程执行,这个时候,为了区分哪些代码能够被(多)线程执行,java就提供了thread类中的run()用来包含哪些被(多)线程执行的代码。 一般来说,被线程执行的代码都是比较耗时的,所以比较简单的就没有必要开创线程。
  9. Run()和start()方法的区别:run()仅仅是封装了线程执行的代码,直接调用跟普通方法一样。Start()方法首先启动了线程,然后再有jvm去调用该线程的run() 方法。  
  10. 针对不是thread类的子类如何获取线程对象的名称?public static thread currenthread():返回当前线程的对象,然后在getname()即可。
  11. Java使用的是抢占模型:优先级高的获得cpu的时间片就多,同一优先级就随便获取一个。
  12. 线程的默认优先级是5.线程的优先级的范围是1~10,最小的是1,最大的是10.
  13. 线程的优先级高仅仅表示线程获取的cpu的时间片的几率高一些,但是要多次运行比较后才能得到比较好的效果,否则一两次有随机性,并不能很好的展现出结果。
  14. 线程的一些控制方法

线程休眠

public static void sleep(long millis)

【以毫秒为单位】

线程加入

【等待该线程终止,别的线程才可以抢】

public final void join()

线程礼让

【暂停当前正在执行的线程对象,并执行其他线程,它可以让多个线程的执行更和谐,但是不能保证一人一次】

public static void yield()

后台线程

【将该线程记为守护线程或用户线程,当正在运行的线程是守护线程时,java虚拟机退出,该方法必须在启动线程前调用】

public final void setDaemon(boolean on)

中断线程

public final void stop()

【让线程停止,已经过时了,不过还可以用,太过暴力,直接停止了,后面的代码就不能运行】

public void interrupt()

【中断线程,把线程的状态终止,并抛出一个异常,好让的代码运行】

  1. 线程的生命周期

      

  1. 实现runnable接口也同样要重写run()方法。然后创建实现类的对象,在创建thread类的对象,将实现类作为参数传递。       
  2.  实现runnable接口的好处

实现接口方式的好处

可以避免由于Java单继承带来的局限性。

适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。

 

  1.  为了实现共享一种资源,可以将这个资源定义为静态的。  
  2. 加入延时后买票出现的问题

相同的票出现多次:

CPU的一次操作必须是原子性的

还出现了负数的票:

随机性和延迟导致的

package cn.itcast_08;

public class SellTicket implements Runnable {

       // 定义100张票

       private int tickets = 100;

@Override

//    public void run() {

//           while (true) {

//                  // t1,t2,t3三个线程

//                  // 这一次的tickets = 100;

//                  if (tickets > 0) {

//                         // 为了模拟更真实的场景,我们稍作休息

//                         try {

//                                Thread.sleep(100); // t1就稍作休息,t2就稍作休息

//                         } catch (InterruptedException e) {

//                                e.printStackTrace();

//                         }

//

//                         System.out.println(Thread.currentThread().getName() + "正在出售第"

//                                       + (tickets--) + "张票");

//                         // 理想状态:

//                         // 窗口1正在出售第100张票

//                         // 窗口2正在出售第99张票

//                         // 但是呢?

//                         // CPU的每一次执行必须是一个原子性(最简单基本的)的操作。

//                         // 先记录以前的值

//                         // 接着把ticket--

//                         // 然后输出以前的值(t2来了)

//                         // ticket的值就变成了99

//                         // 窗口1正在出售第100张票

//                         // 窗口2正在出售第100张票

//

//                  }

//           }

//    }

      

       @Override

       public void run() {

              while (true) {

                     // t1,t2,t3三个线程

                     // 这一次的tickets = 1;

                     if (tickets > 0) {

                            // 为了模拟更真实的场景,我们稍作休息

                            try {

                                   Thread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,

                            } catch (InterruptedException e) {

                                   e.printStackTrace();

                            }System.out.println(Thread.currentThread().getName() + "正在出售第"

                                          + (tickets--) + "张票");

                            //窗口1正在出售第1张票,tickets=0

                            //窗口2正在出售第0张票,tickets=-1

                            //窗口3正在出售第-1张票,tickets=-2

                     }

              }

       }

}   

  1.   解决线程安全问题的基本思想

 首先想为什么出现问题?(也是我们判断是否有问题的标准)

是否是多线程环境

是否有共享数据

是否有多条语句操作共享数据

如何解决多线程安全问题呢?

基本思想:让程序没有安全问题的环境。

怎么实现呢?

把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。      

  1.  同步代码块(可以解决线程安全问题)

同步代码块

格式:

              synchronized(对象){需要同步的代码;}

同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。(这个对象要形成唯一的一把”锁”,定义成成员变量为佳)

  1.  买票的完美代码:

    package cn.itcast_10;

 

public class SellTicket implements Runnable {

// 定义100张票

       private int tickets = 100;

// 定义同一把锁

       private Object obj = new Object();

@Override

       public void run() {

              while (true) {

                     // t1,t2,t3都能走到这里

                     // 假设t1抢到CPU的执行权,t1就要进来

                     // 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。

                     // 门(开,关)

                     synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)

                            if (tickets > 0) {

                                   try {

                                          Thread.sleep(100); // t1就睡眠了

                                   } catch (InterruptedException e) {

                                          e.printStackTrace();

                                   }

                                   System.out.println(Thread.currentThread().getName()

                                                 + "正在出售第" + (tickets--) + "张票 ");

                                   //窗口1正在出售第100张票

                            }

                     } //t1就出来可,然后就开门。(开)

              }

       }

}

package cn.itcast_10;

/*

 * 举例:

 *               火车上厕所。

 * 同步的特点:

 *               前提:

 *                      多个线程

 *         解决问题的时候要注意:

 *                多个线程使用的是同一个锁对象

 * 同步的好处

 *         同步的出现解决了多线程的安全问题。

 * 同步的弊端

 *         当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

 */

public class SellTicketDemo {

       public static void main(String[] args) {

              // 创建资源对象

              SellTicket st = new SellTicket();

// 创建三个线程对象

              Thread t1 = new Thread(st, "窗口1");

              Thread t2 = new Thread(st, "窗口2");

              Thread t3 = new Thread(st, "窗口3");

// 启动线程

              t1.start();

              t2.start();

              t3.start();

       }

}   

  1. 同步方法的格式以及锁对象。格式:将同步关键字写到方法上,它的锁对象是this(表示当前对象),同步代码块的锁对象是任意对象。同步静态方法的对象是当前类的class文件【类的字节码文件对象】,因为只有该class文件才会在静态方法之前。
  2.   

    如何把一个线程不安全的集合类变成一个线程安全的集合类

                     用Collections工具类的方法即可。

  1.  Lock是一个接口。(子类实现然后调用lock()和unlock()方法,此功能就如同synchronized一样,这是jdk1.5的新特性,最好用try…finally语句,因为这样不管怎样都会释放锁)           
  2. 同步可能产生死锁。

     死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

     

  1. 线程间通信问题:不同种类的线程间针对同一个资源的操作。
  2. 消费者和生产者问题要用到等待唤醒机制。【这些方法在object类中,这些方法的调用必须通过锁对象调用】------->>待续

JAVA笔记(十三)

标签:

原文地址:http://www.cnblogs.com/yc74/p/5493398.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!