JAVA基础
Java语言有哪些特点?
1、面向对象编程,让程序的耦合度更低,代码复用性更高。
2、与平台无关(JVM)。
3、可靠安全,支持多线程。
面向对象和面向过程的区别
面向过程:分析解决问题的步骤,然后使用函数将这些步骤一步步实现,在使用的时候调用即可。性能高,单片、嵌入式一般使用面向过程开发。
面向对象:将构成问题的事物分解成多个对象,而对象通过自身属性和行为来描述,实现某种功能直接调用对象相关方法即可。面向对象有封装、继承、多态(同一个行为,不同的实现,即接口引用不同实例)的特性,维护容易、复用简单、扩展性强。比面向过程性能低。
isntanceof关键字的作用,==和equals的区别
isntanceof是一个双目运算符,用于测试一个对象是否是一个类的实例。
object instanceof class
= =:比较的是内存中存放对象的地址,判断是否指向同一个对象。
equals:内部方法同样是使用了==进行比较,但是String类中重写此方法,比较的是字符串是否相等
Java的集合
Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类,数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口:仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序
Map 接口键值对的集合(双列集合)
├———Hashtable 接口实现类, 同步,线程安全,key和value不能为null
├———HashMap 接口实现类,没有同步,线程不安全,key可以有一个null,value可null
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap
注意:不同的对象的hashcode可能相同,一般使用拉链法、开放定址法、再哈希法进行解决。
Java创建对象的方式?
- new创建新对象。
- 反射机制
String className = "java.util.ArrayList";
Class cls = Class.forName(className);
List list = (List) cls.newInstance();
- 采用clone机制。
- 通过序列化机制。
深拷贝和浅拷贝
- 深拷贝:复制的对象的所有变量有含有原来对象的值,其他引用的对象也将指向新的复制过的对象。即将要复制的对象所引用的对象都复制了。
- 浅拷贝:复制了当前对象,引用的对象还是原来的。
关键字
fianl的用法?
修饰的类不可以被继承,方法不可以被重写,变量不可以被改变,jvm将方法或者变量内联。
static的用法?
“static” 是 Java 中的一个关键字,它可以用来修饰变量和方法。
- 修饰变量:当一个变量被声明为 static 类型时,它就不再属于某个对象,而是属于类。这意味着可以通过类名直接访问静态变量。
- 修饰方法:当一个方法被声明为 static 类型时,它就不需要通过对象来访问,而是可以直接通过类名访问。静态方法不能访问非静态成员。
- 需要注意的是,static修饰的成员变量和方法是和类相关的,而不是和对象相关的,它们不随对象的创建而创建,也不随对象的销毁而销毁。因此,静态成员变量和静态方法在程序运行期间始终存在,可以被多个对象共享。
try catch fianlly,try里面有return,fianlly还会执行吗?
执行,fianlly的执行在return之前。
transient关键字?
阻止实例中被此关键字修饰的变量序列化。
exception与error包结构
Java可抛出异常分为三种类型:被检查异常(checkedException),运行异常(RuntimeException),错误(Error)。
- 运行异常(RuntimeException)
ClassCastException:类转换异常
IndexOutOfBoundsException:数组越界异常
NullPointerException:空指针异常
ArrayStoreException:数据存储异常,操作数组是类型不一致
BufferOverflowException:缓冲区越界异常
- 被检查异常(checkedException)
Exception子类中除了运行时异常都是被检查异常。编译器会检查它,要么通过try。。。catch捕获,要么可以通过throws抛出。
常见的有IOException、FileNotFoundException、SQLException等。
- 错误(Error)
资源不足、约束失败等导致程序不能继续运行的错误。
OOM和SOF
- OOM:是 Java 程序在运行时系统内存不足时抛出的一种异常。这种异常的出现通常是因为应用程序在运行过程中创建了太多的对象,以至于系统内存不能满足其需求。此外,还有一些其他因素,例如线程泄漏、内存泄漏、大型数组分配等,也可能导致 OOM 的出现。如果程序因为 OOM 而停止工作,应该采取适当的措施,例如分析内存使用情况并优化代码,或者增加系统的内存大小等。
- SOF:栈溢出(stack overflow)是一种常见的程序错误,是由于程序递归调用层数太多导致的。每一个方法被调用,都会在栈内分配一个栈帧,如果递归调用的层数太多,栈内存就会被占满,最终导致栈溢出。
常见的栈溢出情况:递归调用层数太多;方法内部存在死循环;由于方法调用时,栈内存不足而导致的溢出。
解决栈溢出的方法:减少递归调用的次数;使用循环代替递归;增加栈内存的大小。
线程、程序、进程
- 进程:程序的一次执行过程,是系统运行程序的基本单位,动态。
- 程序:含有指令和数据的文件,存储在磁盘或者其他的数据存储设别中,即静态代码。
- 线程:与进程相似,但比进程更小,一个进程可以有多个线程,同一个进程中的线程共享同一块内存空间和一组系统资源,所以线程的切换比进程的切换快的多。
Java中的IO流
Java的 IO 架构是一个多层次的架构,其中最主要的三个层次是:
- InputStream 和 OutputStream:它们是最底层的 IO 流,它们以字节为单位进行读写。
- Reader 和 Writer:它们是字符流,在 InputStream 和 OutputStream 基础上进行了扩展,以字符为单位进行读写。
- FilterReader 和 FilterWriter:它们是过滤器,可以对读写的数据进行进一步的处理,例如加密、压缩等。
NIO:New io,实现方式不同,NIO用到了块,效率比IO高很多。是Java的一种基于缓冲区(Buffer)、通道(Channel)和选择器(Selector)的IO编程模型。
-
缓冲区(Buffer):NIO中的缓冲区是一个数组,可以存储不同类型的数据,例如字节、字符、整数等。缓冲区可以通过读取和写入来操作其中的数据,并且可以控制数据的读写位置和容量。
-
通道(Channel):NIO中的通道类似于流,可以从通道中读取数据或者将数据写入通道。与流不同的是,通道可以进行非阻塞式的读写操作,并且可以同时进行读写操作,从而提高并发性能。
-
选择器(Selector):NIO中的选择器用于监控多个通道的状态,例如是否有数据可读、是否可以进行写入等。使用选择器可以避免轮询操作,从而提高了程序的性能和效率。
使用NIO实现简单HTTP服务器的Java代码示例
public class HttpServer {
private static final int PORT = 8080;
private static final Charset CHARSET = StandardCharsets.UTF_8;
private static final Path DOCUMENT_ROOT = Paths.get("www");
public static void main(String[] args) throws IOException {
// 创建ServerSocketChannel,并绑定端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(PORT));
serverSocketChannel.configureBlocking(false);
// 创建Selector,并将ServerSocketChannel注册到Selector上
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 阻塞等待Selector中的事件
selector.select();
// 获取所有已经就绪的SelectionKey,并遍历处理
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
// 处理新连接请求
if (selectionKey.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = channel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
// 处理读事件
SocketChannel channel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
buffer.flip();
// 解析HTTP请求
String request = CHARSET.decode(buffer).toString();
String[] lines = request.split("\r\n");
String[] requestLine = lines[0].split(" ");
String method = requestLine[0];
String path = requestLine[1];
// 获取文件路径,并返回HTTP响应
Path filePath = DOCUMENT_ROOT.resolve(path.substring(1));
String response = null;
if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
byte[] content = Files.readAllBytes(filePath);
response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: " + content.length + "\r\n" +
"\r\n" +
new String(content, CHARSET);
} else {
response = "HTTP/1.1 404 Not Found\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: 9\r\n" +
"\r\n" +
"Not Found";
}
ByteBuffer responseBuffer = CHARSET.encode(response);
channel.write(responseBuffer);
// 关闭SocketChannel
channel.close();
}
// 移除已经处理的SelectionKey
iterator.remove();
}
}
}
}
上述代码实现了一个简单的HTTP服务器,它通过ServerSocketChannel监听来自客户端的连接请求,然后将连接分配给新的SocketChannel进行处理。每个SocketChannel通过Selector监听可读事件,当有数据可读时,就将读取到的HTTP请求解析并返回相应的HTTP响应。