![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Java
Java相关知识
jiangkun0331
Bugs总是让我们无法心安
展开
-
Java当中的内存泄漏
内存泄露的原因:1.作用域大小不一样2.长生命周期引用短生命周期3.改变hash值4.用String连接字符串5.一些连接资源没关闭6.静态变量容器7.单例对象引用外部对象怎么避免内存泄露:1.作用域尽量保持一致2.用StringBuffer或者StringBuilder代替String连接字符量3.不再使用的对象值赋值为null4.连接资源的对象要关闭5.尽量少使用静态变量...原创 2020-11-19 15:26:24 · 106 阅读 · 0 评论 -
为什么说ArrayList是线程不安全的?
一.概述对于ArrayList,相信大家并不陌生。这个类是我们平时接触得最多的一个列表集合类。面试时相信面试官首先就会问到关于它的知识。一个经常被问到的问题就是:ArrayList是否是线程安全的?答案当然很简单,无论是背来的还是自己看过源码,我们都知道它是线程不安全的。那么它为什么是线程不安全的呢?它线程不安全的具体体现又是怎样的呢?我们从源码的角度来看下。二.源码分析首先看看这个类所拥有的部分属性字段:public class ArrayList<E> extends Abstr原创 2020-08-11 18:28:12 · 293 阅读 · 0 评论 -
信息小管家
在学习了数据库和Servlet的知识之后,想着写一个项目来练习一下这部分,于是通过学生信息管理系统来完成这个任务项目的主要业务是进行学生信息的管理,包括学生信息的增加,删除,查询,更新通过前端的请求,后端进行响应,返回JSON格式的数据,然后前端进行解析,显示到页面上.数据库设计班级和学生信息表为一对多关系数据字典表和数据字典标签表为一对多关系字典表说明数据字典表和数据字典标签表主要用在一些通用的下拉菜单选项。如班级表中的字段:学生是哪一届的,学生专业如果单独设计需要单独一张表,实际存原创 2020-08-08 23:40:37 · 299 阅读 · 0 评论 -
在浏览器输入URL回车后发生了什么
在浏览器输入URL回车后发生了什么?可以通过两个方面来聊纯应用层的讲述(HTTP协议/DNS协议)从网络原理角度来聊从应用层来说1.用户输入URL,回车之后,可能有浏览器搜索引擎的处理,比如输入一个汉字2.浏览器通过DNS协议来解析域名,如果输入的是ip就跳过这条关于如何域名(domain)解析为 ip浏览器内部有缓存,之前处理过,这个域名,所以就直接返回找操作系统OS帮忙1 /etc/hosts固定hosts2 去 IPv4DNS服务器问 1原创 2020-08-08 14:21:40 · 216 阅读 · 0 评论 -
用Java实现简单HTTP服务器———Tomcat
1. 理解模型首先我们先了解一下tomcat的大致工作原理。tomcat的核心是servlet容器,我们称它为CatalinaConnector是用来“连接”容器里边的请求的。它的工作是为接收到每一个 HTTP 请求构造一个 request 和 response 对象。然后它把流程传递给容器。容器从连接器接收到 requset 和 response 对象之后调用 servlet 的 service 方法用于响应。这是自己实现的时候的流程2. 服务器搭建我们先来熟悉一下整个流程构建Htt原创 2020-08-07 17:56:41 · 1936 阅读 · 0 评论 -
Java抽象类实现接口可以不用实现方法
众所周知,在实现类中实现接口时,必须全部重写接口的抽象方法,如public interface MyInter{ function abstract void A(); function abstract voidB();}//实现类中,必须全部重写A和B方法public class MyClass implements MyInter{ public void A(){} public void B(){}}如果不重写接口的方法可以吗?可以,但实现类一定要是一个原创 2020-08-06 18:17:34 · 7004 阅读 · 2 评论 -
Java线程池
1、线程池的优势(1)、降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;(2)、提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;(3)方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换(cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场))。(4)提供更强大的功能,延时定时线程池。2、线程池的主要参数public ThreadPoolExecut原创 2020-06-21 21:15:01 · 161 阅读 · 0 评论 -
生产者消费者模型
生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。真实世界中的生产者消费者模式生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系。比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者(那个吃的)等待如果桌子空了的话。这里桌子就是一个共享的对象。直接使用Java的BlockingQueu原创 2020-06-21 20:42:44 · 172 阅读 · 0 评论 -
实现阻塞队列
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:当队列满了的时候进行入队列操作当队列空了的时候进行出队列操作因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有原创 2020-06-21 20:37:18 · 1083 阅读 · 0 评论 -
单例模式的各种优化
饿汉类加载的时候就创建了实例优点:类加载的时候创建一次实例,避免了多线程同步问题缺点:即使单例没被用到也会创建,浪费内存public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; }}饿汉-原创 2020-06-21 08:56:00 · 250 阅读 · 0 评论 -
Java多线程之Volatile
volatile 修饰的共享变量,可以保证可见性,部分保证顺序性class ThraedDemo { private volatile int n;}可见性:可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比原创 2020-06-21 00:53:12 · 182 阅读 · 0 评论 -
Java多线程之Synchronized
synchronized的底层是使用操作系统的mutex lock实现的。当线程释放锁时,JMM会把该线程对应的工作内存中的共享变量刷新到主内存中当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量synchronized用的锁是存在Java对象头里的。synchronized同步快对同一条线程来说是可重入的,不会出现自己把自己锁死的问题;同步块在已进入的线程执行完之前,会阻塞后面其他线程的进入。语法:修饰方法定义 同步方法修原创 2020-06-20 21:48:22 · 239 阅读 · 0 评论 -
Java多线程总结
1.线程:要解释线程,就必须明白什么是进程进程时系统资源分配的最小单位,线程是系统调度的最小单位。一个进程内的线程之间是可以共享资源的。每个进程至少有一个线程存在,即主线程。1.1 多线程的优势 - 增加运行速度多线程在一些场合下是可以提高程序的整体运行效率的1.2 Java语言中,创建线程的基本方法(本质核心都需要有一个Thread对象出来)创建一个Thread对象 + 关联任务创建一个Thread类,并且复写run方法 (覆写了线程的 任务)new该类的对象原创 2020-06-20 18:43:46 · 576 阅读 · 0 评论 -
关于JVM内存
这是一个比较官方的图JVM 内存模型图Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区: 程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区 下面详细阐述各数据区所存储的数据类型。运行时数据区包括:程序计数器、虚拟机栈、本地方法栈、Java堆、方法区以及方法区中的运行时常量池1、程序计数器: 线程私有,是当前线程所执行的字节码的行号指示器,如果线程正执行一个java方法,计数器记录正在执原创 2020-06-20 10:06:46 · 194 阅读 · 0 评论 -
Java中的引用类型的对象存放在哪里
根据上下文来确定。根据上下文来确定。根据上下文来确定。比如void func(){ Object obj = new Object();//这个obj在函数的栈里。}class Test{ private Object obj = new Object();//这个obj随对应的Test对象分配在堆里}对于方法中的局部变量的引用时存放在java运行时数据区的栈中,对于实例变量则是存放在java运行时数据区的堆中。...原创 2020-06-19 12:04:22 · 3736 阅读 · 1 评论 -
Java 实现七大基本排序算法
一、插入排序原理:整个区间别分为有序区间和无序区间每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入public static void insertSort(int[] array) { int tmp = 0; for (int i = 1; i < array.length; i++) { tmp = array[i]; int j; for (j = i-1; j >原创 2020-06-08 22:40:55 · 264 阅读 · 0 评论 -
Java实现归并排序
原理:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。递归版本思路:当只有一个元素的时候,递归终止先找到中间,然后递归左半边,递归右半边左右都递归完成就进行合并谁小把谁拿下来,当一个完了把另一个拉下来最后把临时数组复制给原来的数组实现代码:import java原创 2020-06-08 22:29:22 · 153 阅读 · 0 评论 -
Java实现快速排序
原理:从待排序区间选择一个数,作为基准值(par);Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据.。递归版本思路:当left >= right的时候就结束递归先找到par然后递归(left,par-1);递归(par+1,right);实现代码:原创 2020-06-08 18:14:32 · 196 阅读 · 0 评论 -
Java为什么不能在方法内定义静态变量
1.由于JAVA规定,方法内定义的都是局部临时变量,且由于内存分配,会创建一个栈帧保存局部变量表、操作数栈,动态链栈等,在方法结束后,栈帧会出栈并释放掉所有局部变量。这个时候定义一个静态变量那会不会造成内存泄漏呢?会的,由于静态变量生命周期同类的对象一致。因此不能。2.在人性化的设计中,静态变量大都用来供外界访问或类中各个方法共享。你在一个方法中定义了一个静态变量,那对于其他方法来说,前者内部是不可见的。且对于外界来说同样也是不可见的。这样便毫无意义。...原创 2020-06-05 17:59:02 · 3130 阅读 · 1 评论 -
实现二叉搜索树
一、概念二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:若他的左子树不为空,则左子树上所有的节点值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树这就是一颗二叉搜索树在这里实现二叉搜索树的插入、查找、删除1.插入这里的插入不考虑插入重复的节点,并且插入的位置一定是叶子节点如果是根节点直接插入定义一个节点cur来遍历,定义一个节点parent来保存父亲节点比当前节点大就咋右边,反之在左边最后看比父亲原创 2020-05-29 09:31:04 · 233 阅读 · 0 评论 -
实现堆Heap
在JDK1.8中的PriorityQueue底层使用了堆的数据结构,而堆实际就是在完全二叉树的基础之上进行一些元素的调整如果有一个关键码的集合K={k0,k1,k2,k3,…,kn-1},把他的所有元素按完全二叉树的顺序存储方式存储,在一个一维数组中,并满足:Ki <= K2i + 1 且 Ki <= K2i + 2(Ki >= K2i + 1且 Ki >= K2I + 2)i = 0,1,2…,则称之为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或原创 2020-05-23 21:12:06 · 251 阅读 · 0 评论 -
判断一棵树是不是完全二叉树
首先要知道什么是完全二叉树?完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。(来自百度)就是长这个样子我们怎么用代码实现呢?原理和层序遍历差不多往队列里面加的时候不管他的左右节点是不是空,都往进加出队列的时候如果遇到一个空,就跳出循环看后面的是不是都是空如果队列里面的都是空,那就是完全二叉树,否则不是代码:class Node { in原创 2020-05-21 00:03:35 · 174 阅读 · 0 评论 -
二叉树的层序遍历
完成二叉树的层序遍历的时候,需要维护一个队列先把二叉树的根节点放进队列然后弹出根节点,看根节点的左右节点是否为空不为空就加入队列不停的弹出队头元素,往队尾添加左右节点队列为空就完成层序遍历代码:class Node { int val; Node left; Node right; Node() {} Node(int val) { this.val = val; } Node(int val, Node left, Node right) {原创 2020-05-20 23:34:23 · 181 阅读 · 0 评论 -
二叉树的递归与非递归遍历
遍历二叉树是一个老生常谈的话题我们可以通过递归的方法来实现,但有时候面试官问能否用非递归来实现?所以我们要都会!通常情况下非递归遍历无非就是采用循环、栈、队列来实现递归遍历的实现代码比较少,我们把二叉树的子问题分析清楚,就不用深究递归到底是怎么递归的了,只要明白宏观上的原理就好了递归前序遍历二叉树 //递归 public List<Integer> preorderTraversal(TreeNode root) { List<Integer> l原创 2020-05-20 00:07:36 · 195 阅读 · 0 评论 -
Comparable和Comparator
Java当中如何实现比较自定义类型的大小呢?在Java当中,自定义类型不可以通过> < =来比较,一般有3种方式来实现:Comparable、Comparator、equals()今天先学习Comparable ComparatorComparableComparator一般用于定义类的时候,实现该接口一般用于定义某个比较器的同时实现该接口注意重写方法:compareTo注意重写方法:compare优点:可以实现自定义类的比较方式优点:可以根据不同的原创 2020-05-19 15:07:59 · 153 阅读 · 0 评论 -
Java实现二叉树的基本操作
二叉树概念二叉树:是每个结点最多有两个子树的有序树,在使用二叉树的时候,数据并不是随便插入到节点中的,一个节点的左子节点的关键值必须小于此节点,右子节点的关键值必须大于或者是等于此节点,所以又称二叉查找树、二叉排序树、二叉搜索树。完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。满二叉树:除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。二叉树的特点(1)树.原创 2020-05-18 00:39:53 · 882 阅读 · 1 评论 -
设计循环双端队列
众所周知,队列是先进先出,队尾进,队头出那么怎么来实现双端循环队列呢?我们知道实现循环队列中比较难的地方队尾进,队头出在于怎么让rear + 1就到数组的front 或者 出队的时候怎么让front到front 我们可以这样:rear = (rear + 1) % length或者front = (front + 1) % length这样就完美解决问题可是加上队头进,队尾出这个功能后,出现的问题是队尾和队头怎么往前走当队头在数组的首元素时,从队头入队势必要从数组的头转变到数组的尾巴,同理当队尾原创 2020-05-18 00:27:21 · 167 阅读 · 0 评论 -
实现循环队列
可以用一个数组来实现一个队列,那如果将数组的尾巴和头连接起来,是不是构成一个循环队列了呢从顺序队列到循环队列设计的思想:rear表示当前可以存放的数据元素的下标front == rear 队列是空的浪费一个空间,如果rear的下一个是front 就认为是满的出队列就是front后移实现中比较难的地方在于怎么让rear + 1就到数组的front 或者 出队的时候怎么让front到front我们可以这样:rear = (rear + 1) % length或者front = (front原创 2020-05-18 00:12:18 · 323 阅读 · 2 评论 -
实现队列 Queue
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO (First In First Out)入队列:进行插入操作的一端称为队尾出队列:进行删除操作的一端称为队头实现:是用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率比较低链式队列 尾插定义两个引用,一个头 一个尾 为了入队出队都实现O(1)的时间复杂度实现代码:class Node { public int data; public Node ne原创 2020-05-17 23:41:18 · 170 阅读 · 0 评论 -
实现栈 Stack
栈是Vector的一个子类,它实现了一个标准的后进先出的栈栈是一种数据结构实现Java语言中的栈(Stack),采用数组来实现import java.util.Arrays;//顺序栈 使用数组//(还可以用链式栈 链表实现 头插尾插都可以,头插复杂度低)public class MyStack<T> { public T[] elem;//数组 public int top;//表示当前可以存放数据元素的下标 public MyStack() {原创 2020-05-17 23:12:04 · 689 阅读 · 0 评论 -
Java中自动装箱和自动拆箱原理
包装类的自动装箱和自动拆箱是JDK1.5的新特性在学习包装类的使用的时候,会学习到装箱(boxing)和拆箱(unboxing),看下面的代码:int i = 10;//装箱操作,建一个Integer类型对象,将i的值放入对象的某个属性中Integer ii = Integer.valueOf(i); Integer ij = new Integer(i);//拆箱操作,将Integer对象中的值取出,放到一个基本数据类型中int j = ii.valueOf();一、了解自动装箱的过程原创 2020-05-17 22:21:21 · 458 阅读 · 0 评论 -
实现String类
Java创建一个MyString类,模拟实现字符串的基本操作实现构造方法实现length实现equals实现compareTo实现toCharArray实现contains实现indexOf实现replaceAll实现replaceFirst实现splitimport java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * @author PineappleSnow * @vers原创 2020-05-09 13:56:50 · 290 阅读 · 0 评论 -
浅谈Java中的String
1.创建字符串 String str = "hello"; System.out.println(str); String str2 = new String("abcdef"); System.out.println(str2); char[] val = {'a','b','c','d','e','f'}; S...原创 2020-05-07 20:16:50 · 772 阅读 · 0 评论 -
继承 多态 抽象类 接口
什么是多态:思想1、父类引用 引用子类对象2、父类和子类有同名的覆盖方法3、通过父类引用代用这个重写的方法的时候。 多态。父类引用 引用子类对象 向上转型//父类引用 引用子类对象 向上转型Animal animal = new Cat("初一","胡子");抽象类:1、抽象方法:一个方法如果被abstract修饰,那么这个方法就是抽象方法。抽象方法可以没有具体...原创 2020-04-29 14:23:58 · 269 阅读 · 0 评论 -
实现不带头结点的单链表
我们知道LinkedList的实现是用链表实现,那我们不妨来手动实现一下LinkedList先把链表的一个节点定义出来class Node { int data; Node next; public Node(int data) { this.data = data; this.next = null; }}接着我们来实...原创 2020-04-24 15:36:11 · 2179 阅读 · 0 评论 -
实现ArrayList
我们知道ArrayList的底层是用数组实现的,那我们不妨来手动实现一下ArrayLlist首先定义ArrayList所需要的成员变量,用一个int类型的数组,元素的个数(用了多长空间)以及初始容量(先设置为10) public int[] elem;//数组 public int usedSize;//有效的数据个数 public static final int intCapac...原创 2020-04-23 16:15:13 · 452 阅读 · 0 评论 -
二分查找 Java
二分查找public static int binarySearch(int[] arr,int key) { int left = 0; int right = arr.length; int mid; while(left <= right) { mid = (left + right) / 2;...原创 2020-04-15 22:08:43 · 994 阅读 · 0 评论 -
冒泡排序 Java
冒泡排序//基础版本快排 public static void bubbleSort(int[] array) { for (int i = 0; i < array.length-1; i++) { for (int j = 0; j < array.length-1-i; j++) { if(arra...原创 2020-04-15 22:07:20 · 140 阅读 · 0 评论 -
汉诺塔问题 递归 Java
从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数实现这个算法可以简单分为三个步骤:(1) 把n-1个盘子由A 移到 B;(2) 把第n个盘子由 A移到 C;(3) 把n-1个盘子由B 移到 C;从这里入手,在加上上...原创 2020-04-14 21:00:00 · 306 阅读 · 0 评论 -
String与StringBuffer的区别
String与StringBuffer的区别简单地说,就是一个变量和常量的关系.StringBuffer对象的内容可以修改;而字符串对象一旦产生后就不可以被修改,重新赋值其实是两个对象StringBuffer内部实现方式和字符串不同StringBuffer的在进行字符串处理时,不生成新的对象,在内存使用上要优于串类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入,删除等操作,使...原创 2020-04-07 19:49:17 · 112 阅读 · 0 评论