-
字符串
需要注意,float转long会丢失精度
- StringBuffer与StringBuilder都继承了AbtractStringBuilder类,而AbtractStringBuilder又实现了CharSequence接口,两个类都是用来进行字符串操作的。在做字符串拼接修改删除替换时,效率比String更高。StringBuffer是线程安全的,Stringbuilder是非线程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了synchronized关键字。
- 访问权限
类内部 本包 子类 外部包 public √
√
√
√
protected √
√
√
×
default √
√
×
×
private √
×
×
×
- String str=“aaa”,创建的“aaa”是常量,jvm将其分配在常量池中。String str=new String(“aaa”),创建的是对象,jvm将其分配在堆内存中。
public String(String original) { // other code } 共创建了两个对象,一个是new String(),一个是“abc” str 是创建了一个引用,它是存放在栈内存中的。 new String 是放在堆内存中的,用了new关键字,肯定在堆中; abc 这个其实应该是在常量池中的,常量池是在jvm的方法区里面, 也有人叫做“永久代”,不属于堆也不属于栈,但是在jdk1.7中已经把常量池移到堆内存中去了, 所以这里的“abc”是在堆内存中。jdk1.8将移除永久代。
- String str=“aa”,String s=“aaa”,String aa=aa+s,2个引用,3个对象。“aa"与"bb"都是常量,常量的值不能改变,执行字符串拼接时候会创建一个新的常量”aabbb",将其存放到常量池中。
- short s1= 1; s1 = s1 + 1; 有错误,short类型在进行运算时会自动提升为int类型,也就是说
s1+1
的运算结果是int类型。 - String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4请问s5==s2返回什么?
返回false。在编译过程中,编译器会将s2直接优化为”ab”,会将其放置在常量池当中,s5则是被创建在堆区, 相当于s5=new String(“ab”);
3*0.1==0.3
返回值false,因为有些浮点数不能完全精确的表示出来。- Java基本数据类型字节
类型 字节数 位数 范围 byte 1 8 -2^7 2^7 - 1 char 2 16 short 2 16 -2^15 2^15 - 1 float 4 32 int 4 32 -2^31 2^31 - 1 long 8 64 -2^63 2^63 - 1 double 8 64 - 函数floor、round、ceil
floor不大于他的最大整数 round 4舍5入->入的时候是到大于他的整数,算法为Math.floor(x+0.5),再向下取整 ceil 不小于他的最小整数
Math.floor Math.round Math.ceil 1.6 1 2 2 1.5 1 2 2 1.4 1 1 2 -1.4 -2 -1 -1 -1.5 -2 -1 -1 -1.6 -2 -2 -1
-
方法和类
- 类加载顺序:父类静态对象和静态代码块==》子类静态对象和静态代码块==》父类非静态对象和非静态代码块==》父类构造函数==》子类非静态对象和非静态代码块==》子类构造函数。
- 在Java中一个unicode占2个字节(byte),1个字节为8比特位(bit),每个unicode码占用16个比特位。
- 方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或者类型不同即可。构造方法可以重载,必须重写。同名不同参,返回值无关。
- 重载和重写都是Java多态的表现。重载(override)在同一个类中多态表现,同名方法、不同参数个数或参数类型。重写(overwrite)是字符类中多态表现,子类出现父类相同方法,返回值必须与父类一直,子类异常类型小于父类异常类型。覆盖/重写:同名同参
- 子类重写了父类方法和属性,访问的是父类的属性,调用的是子类的方法。
-
Math类常用方法:
Pow():幂运算 Sqrt():平方根 Round():四舍五入 Abs():求绝对值 Random():生成一个0-1的随机数,包括0不包括1
- String类常用方法:
charAt:返回指定索引处的字符 indexOf():返回指定字符的索引 replace():字符串替换 trim():去除字符串两端空白 split():分割字符串,返回一个分割后的字符串数组 getBytes():返回字符串的byte类型数组 length():返回字符串长度 toLowerCase():将字符串转成小写字母 toUpperCase():将字符串转成大写字符 substring():截取字符串 format():格式化字符串 equals():字符串比较
- Java中既有单继承(类),又有多继承(接口)。
- 实体类设计规范参考https://www.cnblogs.com/Echoer/p/4567240.html
- 抽象类可以没有抽象方法,包含抽象方法的类一定是抽象类。不能用final修饰抽象来,因为定义抽象类就是让其他继承的,而final修饰类表示该类不能被继承,与抽象类的理念违背了。普通类不能包含抽象方法而抽象类可以,抽象类不能被实例化而普通类可以直接实例化。
- 常见的编译时异常类:
NullPointerException:空指针异常 ArrayIndexOutOfBoundsException:数组下标越界 NumberFormatException:数字转换异常 IllegalArgumentException:参数不匹配异常 InstantiationException:对象初始化异常 ArithmeticException:算术异常
- 处理异常机制:1、异常捕捉try…catch…finally,2、异常抛出throws。
- 自定义一个异常:继承一个异常类,通常是RumtimeException或者Exception。
- 在异常捕捉时,如果发生异常,try.catch.finally块外的return语句会执行,如果有finally在finally后被执行,如果没有,在catch后执行。
- Error与Exception区别?
Error和Exception都是java错误处理机制的一部分,都继承了Throwable类。 Exception表示的异常,异常可以通过程序来捕捉,或者优化程序来避免。 Error表示的是系统错误,不能通过程序来进行错误处理。
- 在使用jdbc的时候,使用PreparedStatement类,而不是使用Statement类,可以防止出现sql注入的问题。
- IO流分类:功能(输入流input、输出流output),类型(字节流、字符流)。
以字节为单位输入输出数据,字节流按照8位传输 以字符为单位输入输出数据,字符流按照16位传输
- 线程同步的方法
wait():让线程等待。将线程存储到一个线程池中。 notify():唤醒被等待的线程。通常都唤醒线程池中的第一个。让被唤醒的线程处于临时阻塞状态。 notifyAll(): 唤醒所有的等待线程。将线程池中的所有线程都唤醒。
- 如果对象的引用被置为null,垃圾收集器在下一个垃圾回收周期中,这个对象将是可被回收的。
- 数据库连接是非常消耗资源的,影响到程序的性能指标。连接池是用来分配、管理、释放数据库连接的,可以使应用程序重复使用同一个数据库连接,而不是每次都创建一个新的数据库连接。通过释放空闲时间较长的数据库连接避免数据库因为创建太多的连接而造成的连接遗漏问题,提高了程序性能。
- 数据库优化
1. 选择合适的字段,比如邮箱字段可以设为char(6),尽量把字段设置为notnull,这样查询的时候数据库就不 需要比较null值 2. 使用关联查询( left join on)查询代替子查询 3. 使用union联合查询手动创建临时表 4. 开启事物,当数据库执行多条语句出现错误时,事物会回滚,可以维护数据库的完整性 5. 使用外键,事物可以维护数据的完整性但是它却不能保证数据的关联性,使用外键可以保证数据的关联性 6. 使用索引,索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快的多的速度检索特定的 行,特别是对于max,min,order by查询时,效果更明显 7. 优化的查询语句,绝大多数情况下,使用索引可以提高查询的速度,但如果sql语句使用不恰当的话,索引无 法发挥它的特性。
- Tomcat服务器优化(内存,并发连接数,缓存)
1. 内存优化:主要是对Tomcat启动参数进行优化,我们可以在Tomcat启动脚本中修改它的最大内存数等等。 2. 线程数优化:Tomcat的并发连接参数,主要在Tomcat配置文件中server.xml中配置,比如修改最小空闲连接 线程数,用于提高系统处理性能等等。 3. 优化缓存:打开压缩功能,修改参数,比如压缩的输出内容大小默认为2KB,可以适当的修改。
-
接口
- 集合
-
区别
- final、finalize()、finally
性质 final为关键字; finalize()为方法; finally为区块标志,用于try语句中; 作用 final为用于标识常量的关键字,final标识的关键字存储在常量池中; finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证; finally{}用于标识代码块,与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常), 该代码块之中的程序必定会进行;
- 抽象类和接口的区别
抽象类: 抽象方法,只有行为的概念,没有具体的行为实现。使用abstract关键字修饰,没有方法体。子类必须重写这些抽象方法。 包含抽象方法的类,一定是抽象类。 抽象类只能被继承,一个类只能继承一个抽象类。 接口: 全部的方法都是抽象方法,属型都是常量 不能实例化,可以定义变量。 接口变量可以引用具体实现类的实例 接口只能被实现,一个具体类实现接口,必须实现全部的抽象方法 接口之间可以多实现 一个具体类可以实现多个接口,实现多继承现象
- hashCode()和equals()
HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值 的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的 hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。 同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重 要。equals()和hashCode()的实现应该遵循以下规则: (1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。 (2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。
- HashMap遇见哈希冲突会如何怎么办?
HashMap初始长度为16,HashMap的长度是2的幂;
使用链地址法,将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。链地址法 - ConcurrentHashMap和Hashtable的区别
它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,jdk1.8之前在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。jdk1.8之后Segment虽保留,但已经简化属性,仅仅是为了兼容旧版本,使用和HashMap一样的数据结构每个数组位置使用一个锁。 - HashMap是线程安全的吗?HashMap在高并发下会有什么问题?
HashMap的容量是有限的。当经过多次元素插入,使得HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高。这时候,HashMap需要扩展它的长度,也就是进行Resize。影响发生Resize的因素有两个: Capacity -> HashMap的当前长度。上一期曾经说过,HashMap的长度是2的幂。 LoadFactor -> HashMap负载因子,默认值为0.75f。 衡量HashMap是否进行Resize的条件如下: HashMap.Size >= Capacity * LoadFactor 扩容 -> 创建一个新的Entry空数组,长度是原数组的2倍。 ReHash -> 遍历原Entry数组,把所有的Entry重新Hash到新数组。 为什么要重新Hash呢?因为长度扩大以后,Hash的规则也随之改变。 Hash公式: index = HashCode(Key) & (Length - 1) 当原数组长度为8时,Hash运算是和111B做与运算;新数组长度为16,Hash运算是和1111B做与运算。Hash结果显然不同。
- ConcurrentHashMap的原理
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的 - HashMap和HashTable
1、HashMap是非线程安全的,HashTable是线程安全的。 2、HashMap的键和值都允许有null值存在,而HashTable则不行。 3、因为线程安全的问题,HashMap效率比HashTable的要高。 4、Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。 一般现在不建议用HashTable, ①是HashTable是遗留类,内部实现很多没优化和冗余。②即使在多线程环境下,现 在也有同步的ConcurrentHashMap替代,没有必要因为是多线程而用HashTable。 ① 继承不同。 public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map ② Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以 直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。 ③ Hashtable中,key和value都不允许出现null值。 在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回 null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由 get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。 ④ 两个遍历方式的内部实现上不同。 Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。 ⑤ 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。 ⑥ Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小 是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
- HashMap和TreeMap
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进 行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为 TreeMap进行有序key的遍历。
- ArrayList和Vector
ArrayList和Vector在很多时候都很类似。 (1)两者都是基于索引的,内部由一个数组支持。 (2)两者维护插入的顺序,我们可以根据插入顺序来获取元素。 (3)ArrayList和Vector的迭代器实现都是fail-fast的。 (4)ArrayList和Vector两者允许null值,也可以使用索引值对元素进行随机访问。 以下是ArrayList和Vector的不同点。 (1)Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。 (2)ArrayList比Vector快,它因为有同步,不会过载。 (3)ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。
- Array与ArrayList
Array可以容纳基本类型和对象,而ArrayList只能容纳对象。 Array是指定大小的。ArrayList初始值是10,每次增长长度为原来的一半。 如果指定了容量 但容量小于10 第一次扩容也是10 Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。尽管ArrayList明显是更好的 选择,但也有些时候Array比较好用。 (1)如果列表的大小已经指定,大部分情况下是存储和遍历它们。 (2)对于遍历基本数据类型,尽管Collections使用自动装箱来减轻编码任务,在指定大小的基本类型的列表上 工作也会变得很慢。 (3)如果你要使用多维数组,使用[][]比List Array与ArrayList都是用来存储数据的集合。ArrayList底层是使用数组实现的,但是arrayList对数组进行了 封装和功能扩展,拥有许多原生数组没有的一些功能。我们可以理解成ArrayList是Array的一个升级版。
- ArrayList与LinkedList有什么区别?
ArrayList与LinkedList都实现了List接口。 ArrayList是线性表,底层是使用数组实现的,它在尾端插入和访问数据时效率较高, Linked是双向链表,他在中间插入或者头部插入时效率较高,在访问数据时效率较低
-
Java集合框架:Collection、Map,Collection接口下的集合框架:List(线性表,顺序存储可有重复值)、Set(无序集合,无序存储不能有重复值)。Map特点:键值对存储数据、元素存储顺序是无序的、不允许出现重复键。
-
框架
- Spring--七大核心模块
核心容器(Spring Core)
核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
应用上下文(Spring Context)
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring面向切面编程(Spring AOP)
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
JDBC和DAO模块(Spring DAO)
JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
对象实体映射(Spring ORM)
Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
Web模块(Spring Web)
Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
MVC模块(Spring Web MVC)
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。