【Java面试】20224年3月最新面试题系列 之 JavaEE

一、JavaEE

A、基础
//1、接口的幂等性怎么解决
8、接口API幂等性:对外提供接口为了支持幂等调用,接口中必须传两个参数:1、source来源 2、来源方序列号seq,这两个字段在提供方系统做联合唯一索引。当第三方调用时,必须先在系统中查询一下是否已经处理过,并返回相应的结果。如果没有处理过再处理。
  
1、查询操作:在数据不变的情况下,查询一次和查询多次结果一样。select天然幂等
2、删除操作:删除一个和删除多个结果都是为空,也是幂等性操作。只是删除多个返回多个结果
3、唯一索引:防止新增脏数据。支付宝的资金账户,只允许用户有一个资金账户。给资金账户表中的用户id添加唯一索引,就可以保证用户只有一个资金账户。
4、token机制:防止页面的重复提交。由于网络原因或导致重复点击造成的页面重复提交,为了只提交一次,集群环境:可以采用token+redis(redis是单线程的,实现顺序性)。单JVM环境:采用token+redis或者token+jvm内存。处理流程:1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token设置有效时间;2. 提交后后台校验token,校验成功删除token,生成新的token返回。token特点:要申请,一次有效性,可以限流。注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题。
5、悲观锁:获取数据时加锁处理。但id字段一定得是主键索引或者唯一索引,不然会锁表。同时悲观锁使用时会伴随事务一起运行,锁定数据时间会比较长。
6、乐观锁:乐观锁在更新数据那一刻上锁,其他时间不上锁,相对于悲观锁效率高。可以采用版本号实现。但数据更新最好用唯一索引或主键更新,这样是行锁。不然会造成表锁情况。
7、分布式锁:分布式系统中唯一索引确定比较困难,所以可以采用分布式锁(通过Redis或者zookeeper实现),在业务系统插入数据或更新数据获取分布式锁,然后做操作,之后再释放锁。这是分布式系统中的思路。(如果某个流程要求不能并发执行,可以在执行之前根据id+后缀的形式获取分布式锁,其他流程获取锁就会失败,保证同一时间只有此线程一个可以执行成功。执行完成后再释放锁)

//2、说说用过哪些集合
集合:MAP + Collection
Map:hashmap、treemap、hashtable、linkedhashmap
CollectionList + set + Queue
  
List:arraylist、linkedlist、vactor
Set:hashset、linkedhashset、treeset
  
list:是有序的,可重复的
  arrayList:底层是数组,查询快,增删慢,线程不安全
  linkedList:底层是链表,查询慢,增删快,线程不安全
  vactor:底层是数组,查询快,增删慢,线程安全
set:无序的,不可重复的
  hashSet:底层是哈希表,无序的,唯一的。通过hashCode()equals()来保证唯一性
  linkedHashSet:底层是数组+哈希表,有序的,唯一的。通过hashCode()equals()来保证唯一性,通过链表来保证有序性
  treeSet:底层是红黑树,有序的,唯一的。通过自然排序或比较器排序来保证有序性,通过表交返回值是0来确定唯一性
  
Map:k-v型的键值对
  treeMap是有序的,hashMap和hashTable是无序的
  hashTable:方法是同步的,线程是安全的,底层所有public修饰的方法都有synchronized修饰,效率较低。hashTable不允许有null值
  hashMap:方法是不同步的,线程是不安全的,效率较高。hashMap允许有null值(k和v都允许有null值)
  
//3、B-tree和B+tree的区别,估算一千万的B+tree树有多高
1B-tree在非叶子结点和叶子结点都有数据,B+tree只有在叶子结点上有数据,非叶子结点上不存数据,只存索引;
2B-tree叶子结点之间不存在指针,B+tree叶子结点之间存在指针,有利于在每一个节点上开始遍历查找。
  
mysql对每一个节点分配的内存大小约为:16K
每一个非叶子结点可以存放大约1170个索引元素
每一个叶子结点可以存放16个索引元素(一个K+一个V 大小为 1K)
一个三阶B+tree大约可以存放 2100万个数据  1170*1170*16=2100//4、数组和链表的区别
1、链表是链式的存储结构,数组是顺序的存储结构;
2、链表是用指针来链接元素,数组是将元素按次序存储;
3、链表的插入删除元素比数组简单,因为不需要移动元素,而且较容易实现扩容,但是查找某个元素比较困难;数组寻找某个元素比较简单,但插入删除元素比较复杂。由于数组的最大长度在程序初始化是指定,所以扩容比较麻烦。
  
//5、静态代码块和构造方法哪个先执行
静态代码块执行优先于构造方法。因为static修饰的会随着类的加载而加载。
  
//6、类在什么情况下会被初始化
1、创建类的实例时;
2、调用类的成员方法时;
3、访问类的变量或为类的变量赋值时;
4、使用反射方式来强制创建某个类或接口对应的java.lang.class对象时;
5、初始化某个类的子类,这个子类的父类会被初始化;
6、使用java.exe命令运行某个主类,这个主类先被初始化。
  
注:static修饰的属性和方法在类加载时被初始化。普通的属性和方法在创建类的实例对象时才被初始化。
  类在什么时候不被初始化:
  1、通过子类饮用父类的静态字段,子类不会初始化;
  2、通过数组定义来引用类时,不会被初始化;
  3、调用类的常量,类不会被初始化。
  
//7、hash冲突了怎么解决
1、开放地址法
2、再哈希法:产生冲突时,再计算另一个哈希函数地址,知道不在冲突为止。
3、链地址法:将所有哈希地址相同的记录都放在一个链表中(hashMap底层)
4、建立一个公共溢出区:在表外建立一个存放冲突的区域。

//8、set、map、list区别
1、set、list是collection接口下的子接口集合,而map是和collection同级别的接口集合;
2、set集合元素是无序的,唯一的,list集合元素是有序的,可重复的;
3、set和list集合是单节点集合,map是以键值对存在的集合。
  
//9、int与Integer的区别
1int是基本数据类型,Integerint类型的包装类;
2int可以直接使用,Integer必须实例化后才能使用;
3int可以直接存储数值,Integet是一个对象的引用;
4int默认值是0Integer默认值是null//10、==和equals的区别
1==比较的是内存地址,equals比较的是内容
2、基本数据类型只有==,没有equals;
3、对于对象:==比较的是内存地址,equals比较的是值。

//11、做过接口开发吗?


//12、多态的应用
1、父类作为方法的行参;
2、父类作为方法的返回值。

//13、重载和重写的区别、动态绑定和静态绑定的区别
静态绑定:编译时刻由编译器完成,编译时刻就能确定调用的是哪段代码
动态绑定:运行时刻完成类型绑定,编译时刻不知道对象的真实类型,执行的是哪段代码,由运行时刻传入的对象类型来动态决定。
重载:通过调用参数的类型和顺序来确认调用哪个涵数,是静态绑定
重写:是子类重新实现父类的相同签名的涵数,从而改变父类的行为,原先调用父类这个方法的对象,会动态绑定到这个子类的新实现,属于动态绑定。


//14、局部变量和静态变量的区别?哪个更容易导致内存溢出?
1、局部变量只有执行到变量定义的语句时才分配内存,静态变量在编译阶段就已经分配内存;
2、局部变量离开{}作用域就释放内存,静态变量只有程序结束才释放;
3、局部变量不初始化,为随机值,静态变量不初始化为默认值;
4、静态变量只能用敞亮初始化。
  
  静态变量更容易内存溢出。因为静态变量随着类的加载而加载随着程序的结束而终止,就造成了没有被引用还不能被垃圾回收,所以更容易内存溢出。

//15、final、finally、finalize()区别
1final:是修饰符,如果修饰类,此类就不能被继承;如果修饰方法或变量,表示此方法或变量不能被修改;
2finally:是try{}catch{}finally{}的最后一部分,表示无论发生任何情况,都会被执行;
3、finalize:是object类的一个方法,在垃圾回收时会调用被回收对象的此方法。

//16、如何判断一个文件/目录是否存在
1WIN32_FIND_DATA 来判断
2、使用PathFileExists来判断

//17、List<Integer>中的Integer类型中的范型如何拿出
Type[]  getGenericInterfaces():获得当前类实现的类型接口(参数化类型)

//18、深拷贝 浅拷贝
1、深拷贝:把要复制的对象所引用的对象都复制了一遍;
2、浅拷贝:仅仅复制所考虑的对象,而不复制它所引用的对象

//19、同步代码块和同步方法区别
1、同步方法的锁对象是this类,同步代码块的锁对象是obj类;
2、同步方法容易出现问题,锁住了this类,但this中操作的对象那个并不是需要锁的对象;
3、同步代码块只要找准锁对象就好了,但是效率比较低。

//20、BeanFactory 与 FactoryBean 区别
1BeanFactory是一个工厂类,用于管理Bean的一个工厂,在spring中,所有的bean都是有BeanFantoryIOC)容器管理的;
2FactoryBean是一个可以生产或修饰对象生成的工厂bean。他在IOC容器的基础上给bean的实现增加了一个简单的工厂模式和装饰者模式。一般情况下,spring通过反射机制利用<bean>class对象指定实力类实例化bean,但有些时候,实例化的bean过程很繁琐,按照传统方式,需要在配置<bean>中提供大量的配置信息,此时可以实现FactoeyBean接口来定制实例化bean的逻辑。
  
  FactoryBean是一个接口,挡在IOC容器中的bean实现可FactoryBean后,通过getBean(String BeanName)获取到的bean并不是这个FactoryBean的实力对象,而是这个实例类中getObject方法的返回对象。要想获取FactoryBean的实例对象,就需要getBean(&BeanName)加上&//22、十进制如何转二进制
十进制的数除以2取余数,得到的商进行递归,直到商为0。得到的余数倒序的结果即为对应的二进制,如

//23、日志放哪里,用什么工具, 怎么查错误
slf4j工具  日志一般放在系统盘目录下的logging文件目录下

怎么查错误:查看有价值的地方做标记,写入时间线,方便查看哪一步的之前/之后是什么状态,然后找出问题的关键点

//24、binlog日志做什么用的
binlog日志:二进制日志
作用:1、恢复:数据库宕机,使用二进制日志进行Point in time(PIT)恢复;
  	 2、主从复制:实际上通过复制和执行一个二进制文件,来完成主从数据库之间的实时同步;
     3、审计:通过binlog日志中的信息,判断是否有对数据库进行注入攻击
  
  binlog日志保存的什么内容?
  有三种值
  1STATEMENT:记录的是日志的逻辑sql语句,可以减少磁盘IO,提高性能,但有些情况会导致主从数据库数据不一致
  2ROW格式:记录的是对表中行的更改。也就是这一行中的有哪些字段从什么值变成了什么值。可以为复制和恢复带来可靠性,但会增大日志文件的大小;
  3、混合模式:默认情况下使用STATEMENT格式,特殊情况会使用ROW格式(比如用了一些不确定函数)
  
  查看binlog日志 需要使用mysql提供的工具:mysqlbinlog才能查询。

//25、JDk1.8的新特性
1、lambda表达式
2、函数式接口
3、新增了日期类API LocalDataLocalTimeLocalDataTime
4、加入了io


//26、什么是函数式接口,有几种
1、函数式接口:就是只定义了一个没有实现的方法的接口(Object类的public方法除外),注解@FunctionalInterface
  
  常见的函数式接口:
  1Consumer<T> 消费型接口 有参无返回值
  2Supplier<T> 供给型接口 无参有返回值
  3Function<T,R> 函数式接口 有参有返回值
  4Predicate<T> 断言型接口 有参有返回值 返回值是boolean类型

//27、Java中参数传递有几种方式
java中方法参数传递方式是按值传递。
如果参数是基本类型,传递的是基本类型的字面量值的拷贝。
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝
B、List
//1、list的去重的几种实现方式
1、使用 LinkedHashSet 删除 list 中的重复数据,可以保证愿数据顺序
2、利用java8中的stream进行list去重,使用的是stream的distinct()方法返回一个不同数据组成的流,通过对象的equals()方法进行比较
3、利用hashSet不能添加重复数据 去重,不能保证顺序
4、利用list的contains方法循环遍历,重新排序。
5、利用双重for循环,添加判断语句去重。

//2、ArrayList底层
1ArrayList类主要是继承 AbstractList 类并实现了 List 接口,实现 CloneableSerializable 接口使得 ArrayList 具有克隆和序列化的功能。
2ArrayList初始化容量大小为 103ArrayList扩容:当添加数据容量满了以后,检查默认1.5倍的扩容能不能满足,不能满足就按你的需求扩张,但是最大不能超过最大数组长度 128 -8;确定好以后 开辟一个确定好容量长度的新数组拷贝数据。
4ArrayList在进行增删方法时,会抛出“并发修改异常”。因为ArrayList在每次修改容器时,内部都会有一个计数器count进行++操作,在最终遍历时,迭代器会将自己保存的计数器count数值与原容器中的count进行比较是否进行了修改。也就是数组在添加、删除时,count都会增长。
  (解决:1、使用普通 for 循环遍历,不可使用增强 for 循环 2、使用 listIterator 迭代器代替 Iterator 迭代器)
    
//3、ArrayList里面插入10万条数据怎么优化
通过ensureCapacity()提前的对集合的底层数组进行扩容,这样能有效的显著提高执行效率

//4、ArrayList和LinkedList的区别
1ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
2、对于随机访问get和set,ArrayList绝对优于LinkedList,因为LinkedList要移动指针。 
3、对于新增和删除操作add和remove,如果只是单条数据插入或删除,ArrayList比较快,但如果是批量插入或删除,LinedList比较占优势,因为ArrayList要移动数据。

//5、ArrayList初始化大小、如何扩容
1ArrayList的初始化大小为 10 (jdk1.6),之前是初始化大小为 02、当向ArrayList中添加数据时,如果容量已经满了,则按默认的1.5倍扩容看是否能够达到要求,如果达不到,则按你的要求扩容,但是最大不能超过最大数组长度 INTEGER_MAX_SIZE-8    128-8
    
//6、ArrayList创建时为啥最好给一个初始值
如果不指定初始值,JDK1.6以后,默认初始容量为10,当添加的数据超过10,就会以1.5倍的容量进行扩容。如果指定了初始值,则当指定的值不满足后才会扩容。

//7、LinkedList是单向链表还是双向链表
LinkedList是双向链表,从而使添加删除耗时比较短。因为没有索引,所以只能循环遍历,而每次循环遍历时,都会判断一下是属于前半段还是后半段,这样每次遍历其实只遍历了链表的一半,而不是全遍历。

C、Set
//1、HashSet怎么实现去重
依赖于hashCode和equals方法。
1、用hashCode方法获取传入元素的哈希值,在集合中查找是否包含哈希值相同的元素。如果有,则继续用equals方法比较他们的地址值及对象内的属性值,如果全为false,则存入,如果有true则不存入。
D、Map
//1、hashmap底层原理
HashMap底层是一个数组结构,数组中的每一项又是一个链表结构。在JDK1.8以后变成了数组+链表+红黑树
新建一个HashMap时,会初始化一个数组,Entry是以数组中的一个个k-v的形式存在,当要插入一个对象时,会根据哈希算法决定其在数组中的位置,再根据equals方法决定它在数组中链表中的位置。当需要取一个对象时,也会根据哈希算法找到他在数组中的位置,再根据equals方法找到它在链表中的位置。

//2、hashmap扩容机制、初始容量
初始容量:新建一个HashMap时,HashMap是空的,没有初始容量。当添加元素时,会默认容量为16.
源码中HashMap有四种构造函数:1、给定初始容量+加载因子的构造方法;
                         2、给定初始容量+默认的加载因子的构造方法;
                         3、什么参数都不给,使用默认的初始容量+默认的加载因子的构造方法;
                         4、传进一个map,使用默认的加载因子的构造方法。
  所以新建一个HashMap时,HashMap是空的,因为HashMap使用懒加载机制,只有第一次添加元素时才会进行容量设置。
  但是当我们设置初始容量为2N次方时,会按照我们设置的容量设置,当不是2N次方时,会按照设置的那个值找到最接近的2N次方进行设  置。
  
  扩容机制:HashMap的加载因子时0.75,阈值时16*0.75=12.当兼职对的数量大于12时,就会进行扩容操作。扩容以初始容量2倍的形式进行。扩容以后会将原本的数据从新计算元素位置并复制数据。
  为什么是2倍?1HashMap进行扩容计算时,使用的是位运算,更高效;2、因为初始容量是2N次方,扩容以后也是2N次方,可以使添加的元素均匀分布在HashMap的数组上,减少了哈希碰撞,避免形成链表的结构,可以提升查询效率。
  

//3、hashmap安全吗,如何使hashmap线程安全?有哪些集合是安全的
HashMap是非线程安全的。HashMap在处理并发问题时,1、如果此时有多个线程都在put添加元素,正好有两个put的k发生了哈希碰撞,根据HashMap的实现,这两个K会被添加进同一个位置,从而导致其中的一个K被覆盖。2、当多个线程在put添加元素时,都检测到数组需要扩容,就会同时对数组扩容,并且同时重新计算元素的位置并复制数据,但最终只会有一个线程成功操作,其他线程就是操作失败,数据就会被舍弃。
  如何使HashMap安全:1、使用HashTable,因为底层方法都是使用synchronized关键字修饰;
                   2、使用JUC包下的ConcurrentHashMap,使用的是CAS算法;
                   3、使用synchronized Map,底层使用了synchronized同步关键字来保证Map的线程安全问题。

  哪些集合是线程安全的:1List集合下的vector;
                    2Map集合下的HashTable3JUC包下的ConcurrentHashMap4、栈。继承与Vector
  
//4、hashmap的put流程
 1、创建HashMap2、调用put方法,会先计算key的哈希值:hash = key.hashCode()3、调用 tableSizeFor()方法,保证哈希表散列均匀。
 4、计算 Nodes[index]的索引:先进行 index = (tab.length - 1) & hash。
 5、如果索引位为 null,直接创建新节点,如果不为 null,再判断所因为上是否有元素
 6、如果有:则先调用hash()方法判断,再调用 equals()方法进行判断,如果都相同则直接用新的 Value 覆盖旧的;
 7、如果不同,再判断第一个节点类型是否为树节点(涉及到:链表转换成树的阈值,默认 8),如果是,则按照红黑树的算法进行存储;如果不是,则按照链表存储;
 8、当存储元素过多时,需要进行扩容:默认的负载因子是 0.75,如果实际元素所占容量占分约变为原来的2 倍(newThr = oldThr << 1;

//5、并发map的底层原理
并发Map实际上是JUC包下的ConcurrentHashMapJDK1.8前,是分成多个数组,分段加锁,一个数组一个锁。
JDK1.8以后,是一个数组,对每个数组每个元素进行CAS比较加交换。同一个时间,只有一个线程能够成功执行这个CAS,如果这个索引位置是null,则会直接操作,如果已经加锁,说明已经有值,此时测绘基于链表或者红黑树进行处理。通过判断hashcode值及equals方法来判断。

//6、ConcurrentHashMap为什么线程安全?与hashmap的区别
ConcurrentHashMap底层使用synchronized来保证线程安全,在计算size时采用的是CAS比较加交换操作。
 
与HashMap的区别:
1HashMap是线程非安全的,ConcurrentHashMap是线程安全的;
2HashMap本质是数组+链表/红黑树。根据k值取哈希值然后计算数组的下标,如果多个k的下标相同,就用链表串联起来,新添加的在前面。
3ConcurrentHashMap是在HashMap的基础上,将数据分成多个段(segment),默认没个段长度为16,然后每次操作就对一个段加锁,避免多线程锁的机率,提升并发效率。

//7、map可以存空值吗?它的实现中那个可以存空值?那个不可以存空值?为什么
MapKV都可以存空值。
HashMap可以存空值,HashTable不可以存空值,出现空值会报空指针异常。
1HashMap计算key的哈希值时会调用单独的方法,如果是null,则返回0HashTable则直接调用HashCode方法,如果key为null,则抛出空指针异常;
2、以上主要原因是由于Hashtable继承自Dictionary,而HashMap继承自AbstractMap3、虽然ConcurrentHashMap也继承自AbstractMap,但是其也过滤掉了key或value为null的键值对。

//8、map遍历的方式有几种?哪种的效率高
1、如果只是获取key或者value,推荐使用KeySet或者values方式;
2、如果同时需要获取key或者value,推荐使用entrySet;
3、如果在遍历过程中删除元素则使用Iterator4、如果在遍历元素过程中需要增加元素,可以新建一个临时的map存放新增的元素,等遍历完成,再将临时map放到原map中。

//9、hashmap怎么计算哈希值和索引


//10、hashmap和treemap的区别
1、treeMap是有序的,hashMap是无序的;
2、treeMap底层是红黑树,HashMap底层1.8之前数组+链表,1.8以后时数组+链表+红黑树。所以hashMap支持链表操作,treeMap不支持;
3、hashMap有默认初始长度:16及最大长度:2^30,列表转红黑树阈值:8,列表转红黑树最小数组长度:64,而treeMap没有范围限制;
4、hashMap的k和V都可以为null,而treeMap的k不能为null,v可以为null5、hashMap实现的接口为AbstractMap,而treeMap实现的多为NavigableMap6、hashMap的定位由哈希算法定位,针对哈希冲突的值,采用列表和红黑树的方式存储,而treeMap,通过自定义的key比较器或折磨人的比较算法来进行定位红黑树节点的存储位置。
  
  
//11、hashmap和hashtable的区别
1、hashMap的方法不是同步的,hashTable的方法是同步的;
2、hashMap是线程非安全的,hashTable是线程安全的;
3、hashMap效率较高,hashTable效率较低;
4、hashTable底层的公共方法都有synchronized修饰,hashMap没有;
5、hashTable不允许有null值,hashMap中的key和value都允许有null值;
6、hashTable的父类是Dictionary,hashMap的父类是AbstractMap
E、Java面向对象
//1、Java面向对象的思想
面向对象思想就是利用面向对象的特性:封装、继承、多态的特性来不断的创建对象(将对象的属性和行为封装,让二者作为一个整体参与程序执行),然后使用对象,指挥对象做事情。(在已有的对象的情况下,直接使用对象,而不再去考虑对象的内部结构)
  
  封装:隐藏不需要对外公开的属性和方法,以减少对外的耦合(通常将成员变量private,提供对应的getXxx()/setXxx()方法),而对外指通过方法来控制成员变量的操作,提高了代码的安全性,同时把代码用方法进行封装,提高了代码的复用性;
  继承:当多个类有共通的属性(成员变量)和行为(成员方法)时,抽取到另一个类中,让多个类取继承这个父类;
  多态:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
  	多态的成员变量,编译和运行时都参考等号的左边;多态的成员方法,编译时参考等号左边,运行时参考等号的右边
F、IO
//1、stream的简单用法
Stream是通过将集合转换为一种叫做“流”的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列的秉性或穿行的流水线操作;
  
  整个流就是一条流水线,将元素放在流上进行一个个处理。
  其中数据源就是原始集合,然后将如List<T>的集合类型转换为Stream<T>类型的流,并对流进行一些列的中间操作,比如过滤保留部分元素、对集合进行排序、类型转换等,最后再进行一个终端操作调用 collect(toList()) 方法,将Stream转换为集合类型。JDK1.8有了Stream以后,做这些一系列操作就不需要进行迭代器或者foreach循环遍历,而可以直接声明式的下指令,流会帮你完成这些操作。
	
  常用方法:1filter(T->boolean) 保留booleantrue的元素
  				2distinct()去除重复元素,这个方法是通过equals方法来判断两个元素是否相等
          3sorted() 如果流中的元素的类实现了Comparable接口,那么可以直接调用sorted()方法对元素进行排序。
  		    4limit(Long n) 返回前那个元素
          5skip(Long n) 去除前n个元素
  
//2、了解过工作流引擎吗?
工作流引擎:Activiti
  
  工作流:工作流将一套大的业务逻辑分解成业务逻辑段,并统一控制这些业务逻辑段的执行条件,执行顺序以及相互通信。实现业务逻辑的分解和解耦;
  Activiti:是一个开源的工作流引擎,可以发布设计好的流程定义,可以通过Api进行流程调度。
  
  工作流进行的基本过程:
  在框架外定义流程 -> 部署流程定义 -> 启动流程实例,框架移动到任务1 -> 拾取任务组 -> 办理个人业务 -> 框架移动到任务2 -> 拾取任务 -> 办理个人业务。。。
  组任务是多个用户都可以完成的任务,没有组任务直接办理个人任务;有组任务先通过拾取将组任务变成个人任务在进行拾取。

//3、项目中有流的处理吗(字节流、字符流)
字节流:inPutStream、outPutStream   FileInputStreamFileOutputStream
字符流:ReaderWriter  FileReaderFileWriter
  
  
//4、java1.8中如何用stream流进行数据类型转换Object角度考虑:
  Object可以转换成任何包装类型和基本类型;
  Object数组只能转换包装类型数组;
从基本类型和包装类型考虑:
  基本类型的数组,只能由Object转换,也就意味着应当看作Object看待;
  基本类型的多维数组,可以由Object数组转换,但是基本类型数组的维度必须大于Object数组的维度;
  包装类型的数组和多维数组,可以由Object或者Object数组转换,但需要保证包装类型的数组维度不大于object数组的维度。

//5、创建stream的方式
1、值创建流: 可通过 Stream.of() 显示的来创建流,对应流中的参数类型不受限制;
2、数组创建流:可通过 Arrays.stream() 来创建;
3、文件创建流:可通过 Files.lines() 来创建流;
4、函数生成:可以通过 Stream.generate() 或者 Stream.iterate() 来创建流,但是根据函数生成的流没有限制大小,一般需要加上来 limit 控制流的大小
G、通信方式
//1、三次握手、四次挥手
TCP协议,java提供了两个Socket
  1、服务端socket
  	java.net.ServerSocket
  	创建对应的ServerSocket开启服务器,等待客户端链接
    构造方法:Socket accept();监听并且连接,得到一个Socket对象,是一个阻塞方法,始终处于监听状态。返回的是客户端传输过的Socket对象,并使使用的 Socket 和客户端一致。
  
  2、客户端socket
  	java.net.Socket
		创建客户端Socket,并且连接服务器,同时将Socket发送给服务器绑定注册
  	构造方法:Socket(String host, int port)  host是服务器ip地址,port是服务器程序的端口号
  	成员方法:1InputStream getInputStream(); 获取Socket对象输入字节流,从服务器获取对应的数据。Read
  				  2OutputStream getOutputStream();获取Socket对象输出字节流,可以讲数据发送到服务器。Write
            3void close(); 关闭客户端Socket4void shutDownoutput(); 禁止当前Socket发送数据。
  
  3、文件上传操作 客户端程序流程:
  	1. 创建对应文件的输入字节流操作,这里可以使用缓冲
		2. 启动Socket3. 获取Socket输出OutputStream对象,发送数据给服务器
		4. 边读边发
		5. 当文件读取结束,发送完毕,关闭客户端
  
  文件上传操作 服务器程序流程
    1. 开启服务端服务,创建ServerSocket对象
	  2. 明确保存文件的位置,创建对应文件夹的输出缓冲字节流
	  3. 读取数据,写入文件
	  4. 关闭服务器

  三次握手流程:
  1、服务端创建ServerSocket对象,时刻监听客户端消息;
  2、客户端启动Socket,询问服务器端Socket状态,是否可以发送数据;
  3、服务器端响应,调用OutputStream对象输出信息,并断开连接;
  4、客户端调用InputStream接受程序,写入文件,关闭资源,并持续监听客户端;
  
  四次挥手流程:
  1、客户端发送完数据,通知服务器端,并询问是否可以关闭连接;
  2、服务器端响应已经成功接受程序,可以断开;
  3、客户端断开连接,并发送状态给服务器端;
  4、服务器端接受状态。
H、设计模式
//1、手写懒汉式和饿汉式,哪一种是线程安全的?

1/*饿汉式单例模式*/
class Singleton{
 	//创建私有的构造函数,保证外类不能实例化本类
  private Singleton(){}
  //自己创建一个类的实例化
  private static Singleton singleton = new Singleton();
  //创建一个get方法,返回一个实例singleton
  public static Singleton getInstance(){
    return singleton;
  }
}

2/*懒汉式单例模式*/
class Singleton{
 	//创建私有的构造函数,保证外类不能实例化本类
  private Singleton(){}
  //自己创建一个类的实例化
  private static Singleton singleton;
  //创建一个get方法,返回一个实例singleton
  public static Singleton getInstance(){
    //判断singleton是否为空,如果为空,则需要实例化
    if(singleton == null){
      singleton = new Singleton();
    }
    return singleton;
  }
}

3、饿汉式是线程安全的,懒汉式是非线程安全的,可以使用synchronized关键字。
I、排序算法
//1、冒泡排序
public static void ArraySortTest(){
  int[] ages = {1,2,4,5,7,8,23,454,442};
  System.out.println(Arrays.toString(ages));
  for(int i = 0; i < ages.length - 1; i++){
    Boolean flag = false;
    for(int j = 0; j < ages.length - i - 1; j++){
      if(ages[j] > ages[j + 1]){
        int tmp = 0;
        ages[j] = tmp;
        ages[j] = ages[j + 1];
        ages[j + 1] = tmp;
        flag = true;}
      if(!flag){
        System.out.println("已经排好序了")
        break;}}}
  System.out.println(Arrays.toString(ages));}
//2、快速排序
public class QuickSort{
  public static void quickSort(int[] arr, int low, int high){
    int i,j,tmp,t;
    if(low > high){
      return;}
    i = low;  j = high;  tmp = arr[low];
    while(i < j){
      //先看左边,依次往左递减
      while(tmp <= arr[j] && i < j){
        j--;}
      //再看左边,依次往右递减
      while(tmp >= arr[i] && i < j){
        i++;}
      //如果满足条件则交换
      if(i < j){
        t = arr[j];
        arr[j] = arr[i];
        arr[i] = t;}}
    //最后将与i和j相等位置的元素交换
    arr[low] = arr[i];
    arr[i] = tmp;
    //递归调用左边数组
    quickSort(arr, low, j-1);
    //递归调用右边数组
    quickSort(arr, j+1, high);}
  public static void main(String[] args){
    int[] arr = {1,4,6,7};
    quickSort(arr, 0, arr.length-1);
    for(int i = 0; i < arr.length; i++){
      System.out.println(arr[i]);}}}

持续更新中。。。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栈、小生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值