首页 > 编程语言 >Java基础知识面试题系列七:61~70题

Java基础知识面试题系列七:61~70题

时间:2023-09-10 16:02:56浏览次数:43  
标签:面试题 Java Socket 对象 61 70 new 序列化 public



Java基础知识面试题系列七:61~70题

  • 61、Java IO流的实现机制是什么
  • 62、管理文件和目录的类是什么
  • 63、如何列出某个目录下的所有目录和文件
  • 64、Java Socket是什么
  • 65.用Socket实现客户端和服务器端的通信,要求客户发送数据后能够回显相同的数据
  • 66.Java NIO是什么
  • 67.什么是Java序列化
  • 68.需要使用序列化场景
  • 69.什么是Java的反序列化
  • 70.什么是外部序列化


61、Java IO流的实现机制是什么

  • 在Java语言中,输入和输出都被称为抽象的流,流可以被看作一组有序的字节集合,即数据中两设备之间的传输。
  • 流可以分为两大类:字节流和字符流。
  • 字节流以字节(8bit)为单位,包含两个抽象类:InputStream(输入流)和OutputStream(输出流)。
  • 字符流以字符(16bit为单位),根据编码映射字符,一次可以读多个字节,包含两个抽象类,Reader(输入流)和Writer(输出流)。

字节流和字符流最主要的区别为:

  • 字节流在处理输入输出时不会用到缓存,而字符流用到了缓存。
import java.io.*;

class MyOwnInputStream extends FilterInputStream{
    public MyOwnInputStream(InputStream in){
        super(in);
    }

    public int read() throws IOException{
        int c = 0;
        if( (c = super.read())!=-1){
            //把小写转换为大写
            if(Character.isLowerCase((char)c))
                return Character.toUpperCase((char)c);
            //把大写转换为小写
            else if(Character.isUpperCase((char)c))
                return Character.toLowerCase((char)c);
            //如果不是字母,保持不变
            else
                return c;
        }
        else{
            return -1;
        }
    }
}


public class InputStreamTest {
    public static void main(String[] args) {
        int c;
        try{
            InputStream is = new MyOwnInputStream(new BufferedInputStream(new FileInputStream(
                    "test.txt")));
            while((c=is.read())>=0){
                System.out.print((char)c);
            }
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

文本内容为:
hi do you love me? no 22 33 BIG Data
输出如下所示:
HI DO YOU LOVE ME? NO 22 33 big dATA

62、管理文件和目录的类是什么

Java提供了一个非常重要的类来管理文件和文件夹,通过类不仅能够查看文件或目录的属性,而且还可以实现对文件或目录的创建、删除与重命名等操作。

File类常用的方法:

方法

作用

File(String pathname)

根据指定路径创建一个File对象

createNewFile()

若目录或文件存在,则返回false,否则创建文件或文件夹

delete()

删除文件或文件夹

isFile()

判断这个对象表示的是否是文件

isDirectory()

判读这个对象表示的是否是文件夹

listFiles()

若对象代表目录,则返回目录中所有文件的File对象

mkdir()

根据当前对象指定的路径创建目录

exists()

判断对象对应的文件是否存在

63、如何列出某个目录下的所有目录和文件

import java.io.File;

public class ListFile {
    public static void main(String[] args) {
        File file = new File("/Users/bigdata/put");
        //判断目录是否存在
        if(!file.exists()){
            System.out.println("dirctory is empty");
            return;
        }
        File[] fileList = file.listFiles();
        for (int i = 0; i < fileList.length; i++) {
            //判断是否为目录
            if(fileList[i].isDirectory()){
                System.out.println("directory is :" + fileList[i].getName());
            }
            else{
                System.out.println("file is :" + fileList[i].getName());
            }
        }
    }
}

文件输出如下所示:
file is :debezium.tar.gz
file is :.DS_Store

64、Java Socket是什么

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个Socket。

  • Socket称为套接字,可以用来实现不同虚拟机或不同计算机之间的通信。

Java语言中,Socket可以分为两种类型:

  • 面向连接的Socket通信协议(TCP,传输控制协议)
  • 面向无连接的Socket通信协议(UDP,用户数据报协议)
  • 任何一个Socket都是由IP地址和端口号唯一确定的

基于TCP的通信过程如下:

  • 首先,Server(服务器)端Listen(监听)指定的某个端口(建议使用大于1024的端口)是否有连接请求。
  • 其次,Client(客户)端向Server端发出Connect(连接)请求。
  • 最后,Server端向Client端发回Accept(接受)消息
  • 一个连接就建立起来了,会话随机发生。
  • Server端和Client端都可以通过Send、Write等方法与对方通信

Socket的生命周期可以分为3个阶段:

  • 打开Socket
  • 使用Socket收发数据
  • 关闭Socket

在Java语言中,可以使用ServerSocket来作为服务器端,Socket作为客户端来实现网络通信。

65.用Socket实现客户端和服务器端的通信,要求客户发送数据后能够回显相同的数据

Server客户端:

import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        BufferedReader br = null;
        PrintWriter pw = null;
        try{
            ServerSocket server = new ServerSocket(20);
            Socket socket = server.accept();
            //获取输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //获取输出流
            pw = new PrintWriter(socket.getOutputStream(), true);
            String s = br.readLine(); //获取接收的数据
            pw.println(s);            //发送相同的数据给客户端
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                br.close();
                pw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

client客户端:

package com.bigdata.springboot;

import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) throws IOException {
        BufferedReader br = null;
        PrintWriter pw = null;
        try{
            Socket socket = new Socket("localhost", 20);
            //获取输入流与输出流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            pw = new PrintWriter(socket.getOutputStream(), true);
            //向服务器发送数据
            pw.println("hello ,do you love me ?");
            while (true){
                String s = br.readLine();
                if(s!=null){
                    break;
                }
                System.out.println(s);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                br.close();
                pw.close();
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

启动服务器端程序,然后运行客户端程序,客户端将会把从服务器端发过来的“Hello”打印出来。

66.Java NIO是什么

在非阻塞IO(NIO)出现之前,Java是通过传统的Socket来实现基本的网络通信功能的。以服务端为例,其实现基本流程如下所示:

  • open:打开ServerSocket连接
  • accept:接受连接
  • read:读取数据
  • seldf:发送数据
  • close:关闭连接

如果客户端还没有对服务器端发起连接请求,那么accept就会阻塞(阻塞指的是暂停一个线程的执行以等待某个条件发生,例如某资源就绪)。
如果连接成功,当数据还没有准备好时,对read的调用同样会阻塞。
当要处理多个连接时,就需要采用多线程的方式,由于每个线程都拥有自己的栈空间,而且由于阻塞会导致大量线程进行上下文切换,使得程序运行效率非常低。
因此,引入NIO来解决这个问题。

NIO通过Selector、Channel和Buffer来实现非阻塞的IO操作。

Java基础知识面试题系列七:61~70题_序列化

  • NIO非阻塞的实现主要采用了Reactor(反应器)设计模式,这个设计模式与Observer(观察者)设计模式类似,只不过Observer设计模式只能处理一个事件源,而Reactor设计模式可以处理多个事件源。
  • Channel可以被看作一个双向的非阻塞的通道,在通道的两边都可以进行数据的读写操作。
  • Selector实现了用一个线程来管理多个通道(采用了复用与解复用的方式使得一个线程能够管理多个通道,即可以把多个流合并为一个流,或者把一个流分成多个流的方式),类似于一个观察者。
  • 实现时,把需要处理的Channel的IO事件(例如connect、read或write等)注册给Selector。
  • Selector内部的实现原理为:对所有注册的Channel进行轮询访问,一旦轮询到一个Channel1有注册的事件发生,例如有数据来了,就通过传回Selector-Key的方式来通知开发人员对Channel1进行数据的读或写操作。Key封装一个特定Channel1和一个特定的Selector之间的关系。
  • 这种通过轮询的方式在处理多线程请求时不需要上下文的切换,而采用多线程的实现方式在线程之间切换时需要上下文的切换,同时也需要进行压栈与弹栈操作。因此NIO有较高的执行效率。

Buffer用来保存数据,可以用来存放从Channel1读取的数据,也可以存放使用Channel1进行发送的数据。Java提供了多种不同类型的Buffer,例如ByteBuffer、CharBuffer等。通过Buffer,大大简化了开发人员对流数据的管理。

NIO在网络编程中有着非常重要的作用,与传统的Socket方式相比,由于NIO采用了非阻塞的方式,在处理大量并发请求时,使用NIO要比使用Socket效率高出很多。

67.什么是Java序列化

Java提供了两种对象持久化的方式,分别为序列化和外部序列化。

序列化:

  • 在分布式环境下,当进行远程通信时,无论是何种类型的数据,都会以二进制序列的形式在网络上传送。
  • 序列化是一种将对象以一连串的字节描述的过程,用于解决在对对象流进行读写操作时所引发的问题。
  • 序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要时把该流读取出来重新构造一个相同的对象。

如何实现序列化:

  • 所有要实现序列化的类都必须实现Serializable接口,Serializable接口位于java.lang包中,里面没有包含任何方法。
  • 使用一个输出流(例如FileOutputStream)来构造一个ObjectOutputStream(对象流)对象。
  • 紧接着,使用该对象的writeObject(Object obj)方法就可以把obj对象写出(即保存其状态),要恢复时可以使用其对应的输入流。

序列化有两个特点:

  • 如果一个类能被序列化,它的子类也能够被序列化
  • 由于static(静态)代表类的成员,transient代表对象的临时数据,因此被声明为这两种类型的数据成员是不能够被序列化的

Java提供了多个对象序列化的接口,包括ObjectOutput、ObjectInput、ObjectOutputStream和ObjectInputStream。

import lombok.Data;

import java.io.*;
import java.io.FileOutputStream;

@Data
public class People implements Serializable{
    private String name;
    private int age;
    public People(){
        this.name = "tom";
        this.age = 20;
    }

    public static void main(String[] args) {
        People p = new People();
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try{
            FileOutputStream fos = new FileOutputStream("/Users/fei.yang4/put/people.out");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(p);
            oos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        People p1;
        try{
            FileInputStream fis = new FileInputStream("/Users/fei.yang4/put/people.out");
            ois = new ObjectInputStream(fis);
            p1 = (People) ois.readObject();
            System.out.println("name:" + p1.getName());
            System.out.println("age:" + p1.getAge());
            ois.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 由于序列化的使用会影响系统的性能,因此如果不是必须要使用序列化,应尽可能不要使用序列化。

68.需要使用序列化场景

  • 需要通过网络来发送对象,或对象的状态需要被持久化到数据库或文件中
  • 序列化能实现深复制,即可以复制引用的对象

69.什么是Java的反序列化

Java的反序列化:

  • 将流转换为对象。
  • 在序列化与反序列化的过程中,serial-VersionUID起着非常重要的作用,每个类都有一个特定的serialVersionUID,在反序列化的过程UID中,通过serialVersionUID来判定类的兼容性。
  • 如果待序列化的对象与目标对象的serialVersionUID不同,那么在反序列化时就会抛出InvalidClassException异常。
  • 好的编程习惯,最好在被序列化的类中显式地声明serialVersionUID。

自定义serialVersionUID主要有如下3个优点:

  • 提高程序的运行效率。省区计算serialVersionUID的过程
  • 提高程序不同平台上的兼容性。各个平台的编译器在计算serialVersionUID时完全有可能采取不同的计算方式。
  • 增强程序各个版本的可兼容性。对类进行修改,类的serialVersionUID值将会发生变化,导致累在修改前对序列化的文件中修改后无法进行反序列化操作,同样,通过显式声明serialVersionUID也会解决这个问题。

70.什么是外部序列化

Java语言提供了另外一种方式来实现对象持久化,即外部序列化。

public interface Externalizable extends Serializable{
    void readExternal(ObjectInput in);
    void writeExternal(ObjectOutput out);
}

外部序列化与序列化主要的区别在于序列化是内置的API,只需要实现Serializable接口,开发人员不需要编写任何代码就可以实现对象的序列化,而使用外部序列化时,Externalizable接口中的读写方法必须由开发人员来实现。


标签:面试题,Java,Socket,对象,61,70,new,序列化,public
From: https://blog.51cto.com/u_12080573/7426481

相关文章

  • Java基础知识面试题系列六:51~60题
    Java基础知识面试题系列六:51~60题51."=="、equals和hashCode有什么区别52.String、StringBuffer、StringBuilder和StringTokenizer有什么区别53.Java中数组是不是对象54.数组的初始化方式有哪几种55.length属性与length()方法有什么区别56.异常处理的原理是什么57.运行时异常和普通......
  • Java基础知识面试题系列八:81~90题
    Java基础知识面试题系列七:81~90题81.JavaCollections框架是什么82.什么是迭代器83.Iterator与ListIterator有什么区别84.ArrayList、Vector和LinkedList有什么区别85.ArrayList、Vector和LinkedList容器使用场景选择86.HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别87.Hash......
  • JVM调优篇:探索Java性能优化的必备种子面试题
    JVM内存模型首先面试官会询问你在进行JVM调优之前,是否了解JVM内存模型的基础知识。这是一个重要的入门问题。JVM内存模型主要包括程序计数器、堆、本地方法栈、Java栈和方法区(1.7之后更改为元空间,并直接使用系统内存)。正常堆内存又分为年轻代和老年代。在Java虚拟机中,年轻代用于存......
  • 代码随想录算法训练营第四天| 24. 两两交换链表中的节点, 19.删除链表的倒数第N个结点
    24.两两交换链表中的节点mydemo(超时)/***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListNode(intx):val(x),next(nullptr){}*ListNode(intx,Lis......
  • 基于V7 690T+ZYNQ7020的CPCI 双FMC载板
    概要QT7061板卡是一款基于V7+Z7双FPGA的双FMC高性能CPCI载板。主要芯片采用Xilinx公司7系FPGA中最高端的Virtex7中的XC7VX690T-2FFG1761和Zynq7中的XC7Z020-CLG484,组成双FPGA载板。其中XC7VX690T-2FFG1761搭配2组共8片16bit4Gb的DDR3SDRAM(MT41K256M16HA-125ITE),XC7Z020-CLG484搭......
  • CF1570D 题解
    思路分析前言题解区好似没有用哈希的啊。发现大家都在用map来存是否出现过数字,但是需要注意的是,map的单次查询时间复杂度是\(\mathcalO(\logn)\)的,对于大规模的数据就很可能会TLE。所以,我们可以使用哈希的方法来判断数字是否出现过。浅谈哈希哈希,是通过哈希函数将数......
  • 掌握这些面试题和技巧,Android程序员轻松提高拿到offer的概率
    前言在竞争激烈的IT行业,程序员面试成为了每个开发者必须经历的一道关卡。无论是应聘初级岗位还是高级职位,面试都扮演着决定命运的重要角色。然而,对于很多程序员来说,面试过程充满了不确定性和挑战。下面将在面试中,总结出来的一些建议和策略分享给大家。一、了解面试流程与目标:在准备......
  • Spring - IoC相关面试题
    什么是IoC?SpringIoC有什么好处呢?-看看依赖倒置原则IoC(Inversionofcontrol)控制反转。他是一种解耦的设计思想。IoC的思想就是将原本在程序中手动创建对象的控制权,交给Spring框架来管理,从而实现具有依赖关系的对象之间的解耦(IOC容器管理对象,你只管使用即可),降低代码之间......
  • Spring - AOP常见面试题
    Spring-AOP推荐阅读:动态代理(JDKProxy&cjlib)AOP(Aspect-OrientedProgramming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维......
  • Android虚拟机原理面试题汇总(含详细解析 一)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......