JAVA基础相关面试题--04

集合和泛型
集合:
java将一组数据作为一个管理单元进行管理;集合中存储的都是对象类型;8种基本类型转换为8种包装类类型进行存储;
集合分为两大类:
collection接口:set接口、List接口
Map接口:

List:
List集合是一组有序的集合元素,List有下标,可以通过下标访问集合的元素(get方法),
List集合遍历:
标准for循环
增强型的for循环遍历
Iterator迭代器遍历

ArrayList:线性表数组实现。数组读写快,增删慢。
LinkList:线性表(双向链表)读写慢,增删快
Vector:线性表(数组)。是List接口实现子类中的线程安全类。
链表实现和数组实现的异同点(ArrayList和LinkedList的异同点)
ArrayList底层是数组实现的,特点读写快,增删慢。数组连续存储,有下标。集合读写操作频繁时可以使用ArrayList。
LinkedList底层是链表实现的,遍历时需要每次从头到尾一次遍历,所有读写慢,增删快。当集合增删频繁时,可以使用LinkedList。

采用Hash存储的集合都是无序的;
采用链表存储的集合都是有序的;
采用二叉树型结构存储的集合都是排序的;
带有排序规则的集合元素不能为null;
没有排序功能的集合可以为null;

Set接口
set集合是采用hash散列算法进行存储的集合;因为set集合采用hash散列存储,所有没有下标
【原因:散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值】
总结:集合中凡是采用hash散列存储的集合都没有下标,不能通过下标来进行读取元素的值;

Set集合遍历:foreach遍历、Iterator迭代器遍历(没有下标所以不能用for循环遍历)
HashSet:线性表(hash表)
LinkedHashSet:线性表(hash表,双向链表)
TreeSet:树形结构。平衡二叉树

Map接口
Map集合的元素是一个键值对,以键作为存储的标识,进行散列存储;键和值的类型都是对象类型。java中用Entry抽象封装了键值对,map集合中存储的是一个个的键值对,也就是map中存储的是Entry对象,map可以通过get(key)的方法来获得key的值。

Map集合的遍历:
map集合没有迭代器,都是可以获取所有键集合的迭代器,可以获取所有entry集合的迭代器,先取出Key的Set集合或者Entry的Set集合,value的集合,然后对其进行遍历。
HashMap:线性表(hash表
LinkedHashMap:
TreeMap:

是否有序?是否重复?是否可以为null值?是否排序?
有序:存入集合时元素的顺序和取出集合元素时的顺序一致
排序:取出时元素按照自然顺序进行排序

工具类:
Collection、ArrayList工具类、Comparator和Comparable接口
泛型:集合中指定具体的子类类型,可以避免强制类型转换(向下溯型)

@常用的集合类有哪些?具有哪些特性?是否有序?是否可以为null?是否排序?是否重复?每个集合各类底层的数据存储结构?

底层数据结构是否重复是否为空是否有序是否排序
SetHashSet线性表(hash表)
SetLinkedHashSet线性表(hash表,双向链表)
SetTreeSet树形结构,平衡二叉树
ListArrayList线性表数组实现
ListLinkedList线性表(双向链表)
ListVector线性表(数组)
MapHashMap线性表(hash表)
MapLinkedHashMap线性表(hash表,双向链表)
MapTreeMap树形结构,平衡二叉树

@Comparator和Comparable接口的作用和异同点
用于比较的接口,使对象之间有能比较的能力。

    相同:
           Comparator和Comparable都是java的一个接口,并且是用来对自定义的class比较大小的。
            都是用于Set、TreeSet等比较,都可以用于对对象类型的比较。
    不同:
            comparator是比较器,可以直接执行。接口中的compare方法有两个参数,能对基本数据类型做比较,也能对类对象里的元素做比较。
            comparable通过比较实体对象来调用。但是一个实体只能实现一个接口,所以扩展性不是很好。comparaTo方法有一个参数,用于对类对象里的元素进行比较。
public interface Comparable<T>{
    public int comparaTo(T o);
}
x.compareTo(y);//比较x和y的大小,若返回负数,则x<y;若返回正数,则x>y;若返回0,则相等
public interface Comparator<T>{
    int compare(T o1 , T o2);
    boolean equals(Object object);
}
int compare(T o1 , T o2);//比较o1和o2的大小,返回负数,则o1<o2;返回正数,o1>o2;返回0,则o1==o2

@什么是泛型?泛型的好处?泛型和方法重载有什么联系?泛型可以使用基本类型?

泛型是对java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看做是使用参数化类型时指定的类型的一个展位符。泛型最大的优点是消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中,童年故事提高java程序的类型安全,增强程序的可靠性。

泛型的好处:
编译时的强类型检查
消除显示的类型强制转换
更好的代码复用性,比如实现泛型算法。
泛型可以将运行时异常转换成编译阶段的错误。

泛型方法在重载时,不能定义具有相同集合类型参数的重载方法。【原因】java的泛型实际上并不是真正的泛型,他只是在编译的时候的一些限制,用于保证不会出现运行时潜在的类型转换错误,编译之后的class并没有泛型,丢失了泛型信息,所以称为类型擦除。最终编译出来的两个方法都编号才能相同的方法了,所以泛型不能重载。

void method(List<Object> list) {
    System.out.println("List<Object>");
}
​
void method(List<String> list) {
    System.out.println("List<String>");
}
//编译后:
void method(List list) {
}

@@HashMap的底层实现的数据结构是什么?
1.7- 数组+链表; 1.8+ 数组+链表+红黑树 都是如何实现的?
HashMap底层实现是数组+链表结构实现的。数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。
如果定位到的数组位置不含链表(当前Entry的next指向null),那么对于查找,添加操作仅需一次寻址即可。如果定位到的数组包含链表,对于添加操作其事件复杂度为O(n),首先遍历链表,存在即覆盖,否则就新增。对于查找操作来说,通过key对象的equals方法注意比对查找,所以从性能方面考虑,链表出现的越少,性能才会越好。
数据结构的物理存储结构只有两种,顺序存储结构和链式存储结构(栈、队列、树等)。
HashMap的创建:
默认初始化时会创建一个默认容量为16的Entry数组,默认加载银子0.75,同时设置临界值为16*0.75
在这里插入图片描述
@@什么是红黑树?在HashMap中链表是如何转换为红黑树的?为什么使用红黑树?

二叉查找树(BST):
左子树上所有的节点的值均小于或等于他的根节点的值
右子树上所以的节点的值均大于或等于他的根节点的值
左右子树也一定分别为二叉排序树。

红黑树:平衡的二叉查找树,符合二叉查找树的基本特性,但不会让其中一个分支格外长。
节点是红色或是黑色
根节点是黑色
每个叶子的结点都是黑色的空字节(NULL)
每个红色节点的两个子节点都是黑色
从任意节点到其每个叶子的所有路径都包含相同的黑色节点
当删除或插入节点时,会对平衡造成破坏,所以需要对树进行及时调整。

【变色】:
为了重新符合红黑树的规则,尝试把红色节点变为黑色,或者把黑色节点变为红色。
【左旋转】:
逆时针旋转红黑树的两个节点,是的父节点被自己的右孩子取代,而自己成为自己的左孩子。
【右旋转】:
顺时针旋转红黑树的两个子节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。
在这里插入图片描述

@@HashMap的负载因子是0.75;HashMap的初始长度是多少?16 。HashMap是如何扩容的?Map<Stirng , Object> map = new HashMap<>(30); 的初始长度是多少?
按照16的整数倍进行扩容。所以上述语句的初始长度是32.
开辟链表超过八个自动转化成红黑树。访问速度比单纯的链表速度要快
HashMap是如何解决Hash冲突的?
使用拉链法解决Hash冲突。(HashMap使用的方式)当拉链长度>8,转化成红黑树。
再散列法
依次后推法

IO流:
根据流向:
根据传输单位:

@什么是对象流?试讲内存中的某个事件节点的状态信息以字节流的形式持久化到硬盘文件中。
有的时候我们需要将内存中的对象持久化到硬盘上,或者将硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。

@什么是序列化?什么是反序列化?Serarizable接口的作用?(标志性接口)
序列化:
指把堆内存中的java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点,这个过程称为序列化。将数据结构或对象转换成二进制串的过程。

反序列化:
把磁盘文件中的对象数据或把网络节点上的对象数据,恢复成java对象模型的过程。将在序列化过程中所产生的的二进制串转换成数据结构或者对象的过程。

Serarizable接口的作用:
序列化能把堆内存中的对象的生命周期延长,做持久化操作,当下次在需要这个对象的时候,不需要重新new了,直接可以从硬盘中读出出来就可以了。把对象存储到硬盘上的一个文件夹中,文件的标准扩展名是 .object。一个对象只要实现了Serarizable接口,这个对象就可以被序列化。

@Transient关键字作用?是否可以和final、static搭配使用?以及他们之间的区别?
Transient关键字作用:
一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
ransient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
如果在使用序列化对象进行对象传输或者存储时,如果对象中的某个属性字段的值不允许进行序列化处理,则可以使用transient关键字进行修饰可以避免被序列化处理。在使用对象输入流读取或者接受对象输出流序列化的内容时,使用transient关键字修饰的属性的值会初始化为默认值。

final关键字:
被final关键字修饰的类不可以被继承
被final关键字修饰的方法不可以被重写
被final关键字修饰的变量不可以被改变。变量的引用不可变,指向的内容可以发生改变。

static关键字:
被static修饰的变量属于类变量,可以通过 类名.变量名 直接引用,不需要new一个类出来
被static修饰的方法属于类方法,可以通过 类名.方法名 直接引用,不需要new一个类出来
被static修饰属于类的静态资源,是类实例之间共享的。一处改变,处处都改变。

@【编程题】输入一个文件目录,将该文件目录中的文件内容含有“java”关键字的文件进行输出。

@扩展:NIO和NIO2的编程方式?
NIO 新增的类都放在java.nio 包及子包下,NIO将我内奸或文件的一段区域映射到内存或者,这样可以像访问内存一样来访问文件。
Buffer十一个抽象类,最常使用的子类是ByteBuffer,用于在底层字节数组上进行get/set操作。,通常都是通过一个静态方法来获得一个buffer对象。
NIO.2 主要有一下两方面的改进:

  1. 提供了全面的文件IO和文件系统访问支持,新增 java.nio.file 包及其子包。
  2. 新增基于异步的Channel的IO,在 java.nio.channels 包下增加了多个以Asynchronous开头的channel接口和类。
    NIO.2 弥补了NIO的不足,并提供能Path、Paths和Files类

多线程
@什么是进程?什么是线程?进程与线程之间的异同点?
进程:正在执行的程序就是进程。是线程的集合。进程是CPU进行资源分配的基本单位
线程:正在独立运行的一条执行路径,一个独立的执行单元。在进程中一定会有一个线程,这个 线程称为主线程。线程又叫做微进程,一个进程里面可以包括多个线程,进程独占CPU资源
程序 = 数据 + 代码
线程和进程的区别:
多进程之间的数据块是相互独立的,互不影响
多线程之间的数据块可以共享

@线程的状态以及转换方式?进程三态、五态的状态转换图?
三态:就绪、运行、阻塞
在这里插入图片描述
五态:新建、就绪、运行、阻塞、终止
新建态:进程在创建时需要申请一个空白进程管理块,向其中填写控制和管理进程的信息,完成资源分配。
就绪态:进程已经准备好,只要被分配到CPU就能够立刻运行
运行态:进程处于就绪状态被调度后,进入运行态
阻塞态:正在执行的进程由于某些原因而无法运行,进程收到阻塞
终止态:结束进程,或出现错误,或被系统终止,进入终止状态
在这里插入图片描述
@java多线程编程的实现方法?常用的线程操作的方法?
1.使用Thread类方式
继承Thread类 重写run方法
Run方法中就是线程需要执行的任务或者执行的代码
如何调用线程 声明 A a = new A();
启动线程 不是调用run方法 而是调用start方法 a.start();
使用开启多线程后 代码不会从上往下进行执行
2.使用实现runlable接口方式

3.使用匿名内部类方式
4. Callable
5.使用线程池创建线程

常用的线程操作的方法:
线程休眠方法:sleep()
线程让步:yield()
等待其他线程终止:join()方法
线程停止的三种方法:
设置标记位停止线程,可以使线程正常退出
调用stop方法强制停止线程
调用Thread类的interrupt()方法

@多线程中可以直接调用run方法,执行线程吗?
run方法不能启动线程,只有start方法才能真正假期已过信道线程。
调用start()方法后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可运行状态。通过调用jvm,线程Thread会调用run()方法,执行本线程的线程体。

@线程实现之后,调用run方法和start方法有什么区别?
线程类实现后,都可以调用,没有启动线程机制,线程执行机制必须由start方法来启动。
start方法启动线程,真正实现类多线程运行。通过Thread了调用方法run()来完成其运行操作的,这里方法run()成为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程终止,然后CPU再调度其他线程。
run方法当做普通方法的方式调用,程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面代码。线程的执行路径只有一条,这样就没有达到写线程的目的。
线程几个常用的方法?

@线程死锁?线程死锁产生的条件是什么?
线程死锁:
由于两个或多个线程相互持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的Synchronize代码块时,便占有了资源,知道他退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需的资源时,会互相等待对方释放资源,如果线程都不主动释放所占资源,将产生死锁。

四个条件:互斥性、相互等待性、不可剥夺性、请求和保持
打破四个条件中的任意一个就可以打破死锁

@如何避免线程产生死锁?Synchronize关键字的用法?
针对锁顺序死锁:固定加锁的顺序
针对对象之间协作造成的死锁:开放调用
tryLock():使用定时锁
java中使用Synchronize关键字实现同步锁,只能给对象类型加同步锁,不能给基本类型加同步锁。

synchronize关键字被加锁对象必须是对象类型(基本类型使用包装类类型替代)
synchronize加锁对象时引起多线程死锁的关键资源对象。
使用synchronize关键字进行同步时,主要考虑被加锁的对象,以及被加锁对象的粒度大小,被加锁随想的粒度越小越好,因为同步处理是需要系统开销的。
用法:
可以修饰方法,作为同步方法使用
可以修饰语句块,对该语句块进行同步处理。

synchronize(被加锁对象){ 
    同步块语句
}

网络编程
@什么是OIS7层模型和TCP/Ip4层模型

国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)共同出版额开放系统互连的七层参考模型。一台计算机操作系统中的网络过程包括从引用请求到网络介质,OSI参考模型吧功能分为七个分立的层次。

TCP/IP分层模型被称作因特网分层模型、因特网参考模型。TCP/IP协议被组织成四个概念层,其中有三层对应于ISO参考模型中的相应层,TcP/IP协议族并不包含物理层和数据链路层,因此他不能独立完成整个计算机网络系统的功能,必须与其他的协议协同工作。

@OSI7层模型中各层模型的主要协议、运行的设备、端口号有哪些?

OSI7层模型TCP/IP四层概念模型对应网络协议运行的设备端口号
应用层应用层HTTP、TFTP、FTP、NFS、WAIS、SMTP20、21、25、
表示层应用层Telnet、Rlogin、SNMP、Gopher23、161、
会话层应用层SMTP、DNS53、25
传输层传输层TCP、UDP
网络层网络层IP、ICMP、ARP、RARP、AKP、UUCP
数据链路层数据链路层FDDI、Ethernet、Arpanet、PDN、SLIP、PPP
物理层数据链路层IEEE802.1A、IEEE802.2到IEEE802.11

@常用的网络通信协议:TCP、UDP、HTTP、FTP、POP3,SMTP、

@TCP和UDP的区别?以及网络编程实现方式?
TCP协议:
TCP面向连接是可靠的,TCP三次握手建立连接,四次握手释放连接。
TCP网络编程:
使用Socket作为客户端与服务器端ServerSocket通过IP地址+端口号的方式建立连接,使用输出输入流进行信息交互,如果要传输对象流则需要满足序列化的要求。TCP编程是先建立连接通道,然后再传输信息的

UDP协议:
UDP是非面向连接的不可靠的,UDP传输效率比TCP高,但是可靠性比TCP低。

UDP网络编程
客户端和服务器端都是使用DatagramSocket进行信息的发送和接收。发送和接收的信息是存放在DatagramPacket中,数据包中存放了连接服务器的IP地址和端口号。UDP是将传输信息放在数据包中,直接发送到网络上,不需要建立连接通道。

TCP与UDP区别:
TCP面向连接,UDP是无连接的,即发送数据之前不需要建立连接
TCP提供可靠的服务,通过TCP连接传送的数据,无差错、不丢失。不重复、且按序列到达。UDP尽最大努力交付,即不保证可靠交付。
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流,UDP是面向报文的。UDP没有拥塞阻塞控制,因此网络出现拥塞不会使源主机的发送速率降低。
每一条TCP连接只能是点到点的,UDP支持一对一、一对多、多对一和多对多的交互通信。
TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

从解剖学的视角来观察动态操作类构成的一种思想

@什么是反射?反射的作用和意义?什么是Class类?作用是什么?

反射:java反射机制是在运行状态中,对于任意一个实体类,都能够获取这个类的所有属性和方法,对于任意一个对象,都能够调用他的任意方法和属性。这种动态获取类的构造信息以及动态调用实例对象的行为方法的功能成为java语言的反射机制。
java的反射是动态的,在程序运行时才能获取的一些信息和操作。
java的反射机制是对类在运行时的操作,是第三方(外部)的操作,不是类或者实例对象本身的操作。

java的反射机制是采用一种解剖的视角去分析和控制一个类或实例对象的行为动作;不是这个类或实例本身的行为动作。

反射的作用:
通过反射可以是程序代码访问装载到jvm中的类的内部信息
获取已装载类的成员变量信息
获取已装载类的方法
获取已装载类的构造方法信息

class类:
class类是一个抽象封装类。
jvm在反射机制中将一个类的构成信息进行抽象封装,使用class类来进行描述;
class是对某一个类的抽象封装,class是来自于一个具体的类在jvm执行时所获取信息的抽象封装。
class没有公共构造方法,class对象是在加载类时由java虚拟机以及通过调研类加载器中的defineclass方法自动构造的。

class类的获取方式:
类名.class获取
实例变量名.getClass();
Class类提供一个forName的静态方法(反射方式),Class.forName();
包装类.Type获取Class
Class类.getSuperClass

Class类的作用:
获取类中属性的类型、名称、方法、基类等。可以通过class类完成反射。

@使用java在内存中创建一个新对象的方式有哪几种?
new创建: A a = new A();
对象流创建:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Person p5 = (Person) in.readObject();

反射创建: 调用java.lang.Class或者java.lang.reflect.Constuctor类的newInstance()实例方法。

Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee").newInstance();
//或者
Employee emp2 = Employee.class.newInstance();
//或者
Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();

克隆创建:使用以上三种方式的一种

Employee emp4 = (Employee) emp3.clone();

两种newInstance方法的区别:
1.Class类位于java的lang包中,而构造器类是java反射机制的一部分
2.Class类的newInstance只能触发无参数的构造方法创建对象,而构造器类的newInstance能触发有参数或者任意参数的构造方法来创建对象。
3.class类的newInstance需要其构造方法是共有的或者对调用方法可见的,而构造器类的newInstance可以在特定环境下调用私有构造方法来创建。
4.class类的newInstance抛出类构造函数的异常,而构造器类的newInstance包装类一个InvocationTargetException异常。
5.class类本质上调用了反射包构造器类中五参数的newInstance方法,捕获了InvocationTargetException,将构造器本身的异常抛出。

@什么是注解?注解和注释的区别?
注解是java程序中使用原数据对功能代码进行补充说明的一种编程方式。
注解是在jdk1.5以后才支持的
注解使用在类、属性、方法、构造方法、局部变量、参数、枚举类型上,之前用的注解有:@override、@Test

注释与注解的区别:
注释:是对程序的解释说明,是给编程人员阅读理解代码使用,注释不参与程序的编译执行。
注解:是对程序的补充说明,是给jvm在编译运行程序时使用的“注释说明”,注解是参与程序的编译运行的。

注解参与代码运行,注释不参与代码运行

@常用的元注解有哪些?各有什么作用?
进行注解的自定义开发需要使用java提供的四个元注解(注解注解的注解):
@Target
用于指定注解所可以修饰的范围
范围从枚举类 ElementType中获取
如果不写,默认应用范围是所有的可以使用注解的范围;
不写默认是应用于全部;

@Retention
用于指定自定义注解的生命周期长度;
通过RetentionPolicy类中的静态变量指定:
RetentionPolicy.SOURCE
源码级,jvm编译时会直接丢弃,不参与编译;
RetentionPolicy.CLASS 默认值
编译级,注解存活到编译期间,运行期间在被jvm丢弃;
RetentionPolicy.RUNTIME
运行级,注解存活到运行时,从源码、编译、运行注解都存活;
默认值是Class源码级别

@Documented
决定在使用javadoc自动生成的api文档中包不包含该注解信息;
默认不包含;使用该注解表示api中包含该注解的内容;

@Inherited
决定父类的注解可不可以被子类继承到;
默认是不继承;使用该注解表示子类可以继承;

自定义注解的语法:
@元注解
访问控制修饰符 @interface 自定义注解名{
// 注解属性
数据类型 注解属性名() default 默认值;
}

注意:
自定义注解中的注解属性后面带有 () ;

=================================================================

执行子类的构造方法会默认执行父类的构造方法
执行顺序:
静态语句块
非静态语句块或成员变量(二者的先后由位置先后决定)
构造方法

子类创建时会递归调用父类的构造方法
静态代码块只执行一次,非静态代码块每次new时都执行

@@执行顺序:
执行了父类的静态代码块
执行了子类静态代码块
执行了父类非静态语句块或成员变量(二者的先后由位置顺序决定)
执行了父类构造方法
执行了子类非静态语句块或成员变量(二者的先后由位置顺序决定)
执行了子类构造方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值