Java 杂谈JAVA开发互联网科技

Java面试系列 — 基础篇(三)

2018-07-13  本文已影响83人  奋斗的蛐蛐

先整理出一批面试笔试面试题。后续将继续更新,如果本文中出现问题,请及时与蛐蛐联系,蛐蛐马上继续修改,后续也会同步更新。

流的原理

备注: 输入输出是相对于程序而言,而不是相对于源和目标而言

流的分类

流的方向

处理数据单元:

输入流和输出流联系和区别,节点流和处理流联系和区别

字符流字节流联系区别;什么时候使用字节流和字符流?

列举常用字节输入流和输出流并说明其特点,至少5对。

说明缓冲流的优点和原理

序列化的定义、实现和注意事项

想把一个对象写在硬盘上或者网络上,对其进行序列化,把他序列化成为一个字节流。

实现和注意事项

  1. 实现接口Serializable,Serializable接口中没有任何的方法,实现该接口的类不需要实现额外的方法。
  2. 如果对象中的某个属性是对象类型,必须也实现Serializable接口才可以
  3. 序列化对静态变量无效
  4. 如果不希望某个属性参与序列化,不是将其static,而是transient
  5. 串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存
  6. 序列化版本不兼容

使用IO流完成文件夹复制(结合递归)

public class DemoTest {

    public static void main(String[] args) {
        try {
            copyDirectiory("d:/test", "d:/test");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制单个文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @throws IOException
     */
    private static void copyFile(File sourceFile, File targetFile) throws IOException {
        BufferedInputStream inBuff = null;
        BufferedOutputStream outBuff = null;
        try {
            // 新建文件输入流
            inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
            // 新建文件输出流
            outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
            // 缓冲数组
            byte[] b = new byte[1024 * 5];
            int len;
            while ((len = inBuff.read(b)) != -1) {
                outBuff.write(b, 0, len);
            }
            // 刷新此缓冲的输出流
            outBuff.flush();
        } finally {
            // 关闭流
            if (inBuff != null)
                inBuff.close();
            if (outBuff != null)
                outBuff.close();
        }
    }

    /**
     * 复制目录
     *
     * @param sourceDir 源目录
     * @param targetDir 目标目录
     * @throws IOException
     */
    private static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
        // 检查源目录
        File fSourceDir = new File(sourceDir);
        if (!fSourceDir.exists() || !fSourceDir.isDirectory()) {
            return;
        }
        //检查目标目录,如不存在则创建
        File fTargetDir = new File(targetDir);
        if (!fTargetDir.exists()) {
            fTargetDir.mkdirs();
        }
        // 遍历源目录下的文件或目录
        File[] file = fSourceDir.listFiles();
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                // 源文件
                File sourceFile = file[i];
                // 目标文件
                File targetFile = new File(fTargetDir, file[i].getName());
                copyFile(sourceFile, targetFile);
            }
            //递归复制子目录
            if (file[i].isDirectory()) {
                // 准备复制的源文件夹
                String subSourceDir = sourceDir + File.separator + file[i].getName();
                // 准备复制的目标文件夹
                String subTargetDir = targetDir + File.separator + file[i].getName();
                // 复制子目录
                copyDirectiory(subSourceDir, subTargetDir);
            }
        }
    }
}

对象序列化 (Serialization)

对象序列化的条件

如何实现序列化(序列化流)

  1. 创建ObjectOutputStream对象
  2. 调用writeObject()输出对象
Class clazz = new Class();
OutputStream os = new FileOutputStream(new File("d:/test.txt"));
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(clazz);
oos.close();

如何实现反序列化(序列化流)

  1. 创建ObjectInputStream对象
  2. 调用readObject()读取对象
InputStream is = new FileInputStream(new File("d:/java6.txt"));
ObjectInputStream ois = new ObjectInputStream(is);
Class clazz = (Class)ois.readObject();
System.out.println(clazz.getMethod1()+"  "+clazz.getMethod2());

JavaIO体系

分类 字节输入流 字节输出流 字符输入流 字符数出流
抽象基类 InputStream OutputStream Reader Writer
文件 FileInputStream FileOutputStream FileReader FileWriter
数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
抽象基类 FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

final的使用

short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

对于
short s1 = 1; s1 = s1+1;
由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换

switch中能否使用string做参数

在idk 1.7之前,switch只能支持byte, short, char, int或者其对应的封装类以及Enum类型。从idk 1.7之后switch开始支持String

Java反射技术主要实现类有哪些,作用分别是什么?

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中

  1. Class类:代表一个类
  2. Field 类:代表类的成员变量(属性)
  3. Method类:代表类的成员方法
  4. Constructor 类:代表类的构造方法
  5. Array类:提供了动态创建数组,以及访问数组的元素的静态方法

反射的应用场合

在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息

反射的作用

使用反射技术创建对象

1. 通过Class的newInstance()方法

Class clazz=Class.forName("com.fddqq.reflection.Bean");
Object obj=clazz.newInstance();

//相当于执行语句:
Bean bean = new Bean();

2. 通过Constructor的newInstance()方法

Class clazz=Class.forName("com.fddqq.reflection.Bean");
Constructor cons = clazz.getConstructor(String.class,
int.class, float.class );
Object obj = cons.newInstance( "lkl", 32, 56.5f );

//相当于执行语句:
Bean bean=new Bean("lkl",32,56.5f);


obj = clazz.getConstructor().newInstance();
//相当于执行语句:
Bean bean = new Bean();

反射技术优缺点

反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类

反射是其它一些常用语言,如C、C++、Fortran 或者Pascal等都不具备的

Java反射技术应用领域很广,如软件测试、 EJB、JavaBean等

许多流行的开源框架例如Struts、Hibernate、Spring在实现过程中都采用了该技术

反射的缺点

性能问题
使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

使用反射会模糊程序内部逻辑
程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

上一篇下一篇

猜你喜欢

热点阅读