Java琐碎小知识(三)

1、JDK7新增的一个对I/O和NIOAPI有重大影响的特性是java.lang.AutoCloseable接口。目前大多数java.io类都以实现这个接口来支持try-with-resource。Java.nio.file.Files类可以使用Files类创建和删除文件(Files.createFile\delete)与目录(createDirectory\deleteIfexists)、检查文件是否存在(exists)、读取(readAllBytes\readAlllines)和写入文件(write)。但Files读取和写入文件的支持只适用于小文件,对于更大的文件和新增的功能需要使用流。流有四种基本的抽象类:InputStream(字节流)、OutputStream(字节流)、Reader(字符流)和Writer(字符流)。并且由于InputStream和OutputStream没有缓存且读取和写入都是以字节为单位,可以BufferInputStream bis=new BufferInputStream(Files.newInputStream(path,option))来包装。

byte[]readData=new byte[1024];
InputStream inputStream=Files.newInputStream(path1,StandardOpenOption.READ);
OutputStream outputStream=Files.newOutputStream(path2,StandardOpenOption.WRITE);
int i=inputStream.read(readData);

while(i!=-1){
  outputStream.Write(readData,0,i);
  i=inputStream.read(readData);
  }

2、Writer:writer处理的是字符,除了有write(char[])字符外还有字符串参数的Writer(String text 。。。。。)。其子类OutputStreamWriter是字符流与字节流之间的桥梁,可以指定字符集将字符转为字节流。

public class OutputStreamWriterTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
       char[] chars=new char[2];
       chars[0]='\u4F60';
       chars[1]='\u597D';
       Path path=Paths.get("D:\\File\\ow.txt");
       Charset simpleChineseCharset=Charset.forName("GB2312");
       try (OutputStream outPutStream=Files.newOutputStream(path, StandardOpenOption.CREATE);
            OutputStreamWriter writer=new OutputStreamWriter(outPutStream, simpleChineseCharset)){
           writer.write(chars);

    } catch (Exception e) {
        // TODO: handle exception
    }
    }
}

3、Reader:处理的是字符流。其子类InputStreamReader用指定的字符集将字节转为字符。
4、BufferedReader:
优点:1、封装另一个Reader,并提供一个可以提高性能的缓存。
2、提供一个readLine来读取文本行,返回字符串,如到达末尾返回null。
5、随机访问文件:对于文件的随机访问,Java提供了几个类,第一个是java.io.RandomAccessFile类,它易于使用但现在过时了。第二个是java.nio.channels.SeekableByteChannel接口,它用于新开发的应用程序中。SeekableByteChannel既可以执行读出操作,也可以执行写入操作。使用Files类的newByteChannel方法可以得到SeekableByteChannel的实现:public static java.nio.channels.SeekableByteChannel newByteChannel(Path path,Opention… options),其方法需要传递ByteBuffer,int write(java.nio.ByteBuffer buffer)和int read(java.nio.ByteBuffer buffer)

public class SeekableByteChannelTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ByteBuffer buffer=ByteBuffer.allocate(12);
        System.out.println(buffer.position());
        buffer.putInt(10);
        System.out.println(buffer.position());
        buffer.putLong(1234567890L);
        System.out.println(buffer.position());
        buffer.rewind();
        System.out.println(buffer.getInt());
        System.out.println(buffer.getLong());
        buffer.rewind();
        System.out.println(buffer.position());

        Path path=Paths.get("C:/temp/channel");
        System.out.println("--------------------");
        try (SeekableByteChannel byteChannel=Files.newByteChannel(path,StandardOpenOption.CREATE,StandardOpenOption.READ,StandardOpenOption.WRITE);
                ){
            System.out.println(byteChannel.position());
            byteChannel.write(buffer);
            System.out.println(byteChannel.position());

            ByteBuffer byteBuffer3=ByteBuffer.allocate(40);
            byteChannel.position(0);
            byteChannel.read(byteBuffer3);
            byteBuffer3.rewind();
            System.out.println("int:"+byteBuffer3.getInt());
            System.out.println("long:"+byteBuffer3.getLong());
            System.out.println(byteBuffer3.getChar());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

6、对象序列化:即对象持久化,使用两个流:ObjectOutputStream是OutputStream的一个子类,而ObjectInputStream是InputStream的一个子类。为了使对象可以序列化,它们的类必须实现java.io.Serializable接口。这个标记会告诉JVM实现一个类的实例属于某一个类型。如果序列化的对象包含其他对象,那么被包含对象的类也必须要实现Serializable来使被包含的对象可以序列化。对于一些不想被序列化的域可以:transient public int age;来实现。

public class ObjectSeriallizationTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
      Path path=Paths.get("C:/temp/objectOutput");
      Customer customer=new Customer(1,"jack","12 West Cost","basketball","red");
      try (OutputStream outputStream=Files.newOutputStream(path, StandardOpenOption.CREATE);
              ObjectOutputStream oos=new ObjectOutputStream(outputStream)){
              oos.writeObject(customer);
              oos.writeObject("Customer Info");
    } catch (IOException e) {
        // TODO: handle exception
        e.printStackTrace();
    }

      try (InputStream inputStream=Files.newInputStream(path, StandardOpenOption.READ);
              ObjectInputStream ois= new ObjectInputStream(inputStream)){
          Customer customer1=(Customer)ois.readObject();
          System.out.println("First Object");
          System.out.println(customer1.id);
          System.out.println(customer1.name);
          System.out.println(customer1.address);
          System.out.println(customer1.habit);
          System.out.println(customer1.likeColor);

          System.out.println();
          System.out.println("Second object");
          String info=(String)ois.readObject();
          System.out.println(info);

    } catch(ClassNotFoundException ex){
        System.out.println("ClassNotFound"+ex.getMessage());
    }
      catch (IOException e) {
        // TODO: handle exception
          e.printStackTrace();
    }
    }
}

对于自定义序列化可以使用继承Externalizable接口来实现
对象序列化写的比较好的对象序列化

7、嵌套类和内部类:嵌套类是一个声明在另一个类或接口内部的类,它有两种类型:静态内部类和非静态嵌套类,非静态嵌套类也称为内部类。内部类主要有:成员内部类、局部内部类、匿名内部类;
相对于顶层类而言,嵌套类就像特殊的类成员,比如方法和域,例如可以有public、protected、default、private修饰符区别于顶层类。由于静态嵌套类区别于内部类:
》静态嵌套类可以有静态成员,内部类不可以有。
》内部类可以访问外层的静态和非静态成员,包括它的private成员,而静态嵌套类只能访问外层类的静态成员。
》无需先实例化静态嵌套类的外层类就可以实例化静态嵌套类,而实例化内部类则必须先实例化外层类。
内部类的优点:
》内部类可以使用外层类的所有成员包括private(并非直接访问 而是通过内部类的方法返回取得)
》内部类可以帮你完全隐藏类的实现。

  1. 成员内部类:它直接定义在另一个类或接口声明中,只有在引用它的外层实例时,才可以创建成员内部类的实例。在外层类创建内部类时可以直接像普通类创建一样(调用内部类的构造器),但从外层类的外部创建内部类实例需要先实例外层类:OuterClassName1.InnerClassName inner=OuterClassName1.new InnerClassName();
  2. 局部内部类:它是一个内部类,按照定义来说它不是外层类的成员类(因为它的声明不是直接在外层类的声明中),局部类可以生命在任何代码块中,它的作用域是这个块内。可以是方法、if、while块中声明局部类。
public Logger getLogger(){
        class LoggerImpl implements Logger{

            @Override
            public void log(String message) {
                // TODO Auto-generated method stub
                System.out.println(appStartTime+":"+message);
            }
        }
        return new LoggerImpl();//在方法内声明 且需要创建并返回
    }

局部类不仅可以访问外层类的成员,还可以访问局部变量但局部变量必须是final(jdk1.8之前局部变量必须要finnal修饰,但jdk1.8不显式写也可以 效果等同final 主要是局部变量会随着局部方法结束而结束)。

package com.lr.internalclass;
interface PrefixLogger{
    public void log(String message);
}
public class LocalClassTest2 {
 public PrefixLogger getLogger( final String prefix){

     class LoggerImpl implements PrefixLogger{
         public void log(String message){
             System.out.println(prefix+":"+message);
         }
     }
     return new LoggerImpl();
 }

 public static void main(String[] args) {
    LocalClassTest2 test=new LocalClassTest2();
    PrefixLogger logger=test.getLogger("DEBUG");
    logger.log("local class example");
}
}
  1. 匿名内部类:可以用来编写接口实现,还可以扩展抽象类或具体类来创建匿名内部类。
    重点:JVM并不知道嵌套类的概念,是编译器在努力将内部类编译成顶层类,把外层类和内部类名称结合在一起,两者之间用美元符号隔开,形成名称:
    public class Outer{
    class Inner{
    }
    }
    会被编译成两个类:Outer.class和Outer Inner.classOuter I n n e r . c l a s s 而 匿 名 内 部 类 则 编 译 器 会 用 随 机 数 字 给 它 们 取 一 个 名 称 : O u t e r 1.class,Outer$2.class. 嵌套类被实例化,这个实例就是堆中的一个独立的对象,实际上它并不在外层类对象内部。但对内部类而言,他们有对外层类对象的自动引用。这个引用在静态嵌套类实例中并不存在,因为静态嵌套类不能访问外层类的实例成员。
    内部类访问外层类实例成员是因为编译器修改了内部类的构造器:
    public Inner(int value);
    变为
    public Inner(Outer outer,int value);
    所以随之而来的实例化时参数也是默认被传进去的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值