(部分内容是从别的文章整理出来的)
1、使用float或者double类计算会有误差;
Java在允许float或者double类之间计算的时候会有误差;要精确计算用BigDecimal 或者FloatDecimal;
2、字符串操作少用String
StringBuilder和StringBuffer都继承于:AbstractStringBuilder;使用StringBuilder,线程不安全,速度快;
使用StringBuffer,线程安全,速度慢;
要操作少量的数据用 String;
多线程操作大量数据使用StringBuffer;
单线程操作大量数据使用StringBuilder;
3、字符串变量比较时
str.equal("sowhat")跟“sowhat”.equal(str)功能上看是一样的,但是从代码的健壮性来看推荐后者,因为你无法确实str一定是非空,可以避免空指针异常。
4、MyBatis 中使用 # 和 $占位符的区别
①#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;
② $将传入的数据直接显示生成在 SQL 中。
注意:使用 $ 占位符可能会导致 SQL注入攻击,能用#的地方就不要使用 $ ,写 order by 子句的时候应该用$而不是#。用#{}会多个' '导致sql语句失效;此外,还有一个like语句后也需要用${}
5、Mybatis的好处
①把Sql语句从Java中独立出来。
②封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。
③编写Sql语句,会更加的灵活。
④入参无需用对象封装(或者map封装),使用@Param注解
6、反射技术的优点和缺点
在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射。
优点:
1.提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力
2.允许程序创建和控制任何类的对象,无需提前硬编码目标类
缺点:
1.性能问题
2.代码维护问题
3.破坏了封装性以及泛型约束
7、Oracle序列的使用
Oracle序列创建和使用
创建序列
语法 CREATE SEQUENCE 序列名 [相关参数]
参数说明
INCREMENT BY : 序列变化的步进,负值表示递减。(默认1)
START WITH : 序列的初始值 。(默认1)
MAXvalue : 序列可生成的最大值。(默认不限制最大值,NOMAXVALUE)
MINVALUE : 序列可生成的最小值。(默认不限制最小值,NOMINVALUE)
CYCLE : 用于定义当序列产生的值达到限制值后是否循环(NOCYCLE:不循环,CYCLE:循环)。
CACHE : 表示缓存序列的个数,数据库异常终止可能会导致序列中断不连续的情况,默认值为20,如果不使用缓存可设置NOCACHE
修改、删除序列
使用 alter 命令进行修改
使用 drop 命令删除
序列的使用
currval : 表示序列的当前值,新序列必须使用一次nextval 才能获取到值,否则会报错
nextval : 表示序列的下一个值。新序列首次使用时获取的是该序列的初始值,从第二次使用时开始按照设置的步进递增
查询序列的值:select seq_name.[currval,nextval] from dual;
SQL语句中使用:insert into table (id) values (seq_name.nextval)
8、JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。
9、== 和 equals 的区别是什么?
对于基本类型和引用类型 == 的作用效果是不同的:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用是否相同;
- equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。
10、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不对,两个对象的 hashCode()相同,equals()不一定 true。
11、final 在 java 中有什么作用?
- final 修饰的类叫最终类,该类不能被继承。
- final 修饰的方法不能被重写。
- final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改
12、String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象
13、String str="i"与 String str=new String("i")一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。
在Java中有两种创建字符串对象的方式:采用字面值的方式赋值、采用new关键字新建一个字符串对象。
采用字面值的方
采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"aaa"这个对象,如果不存在,则在字符串池中创建"aaa"这个对象,然后将池中"aaa"这个对象的引用地址返回给字符串常量str,这样str会指向池中"aaa"这个字符串对象;如果存在,则不创建任何对象,直接将池中"aaa"这个对象的地址返回,赋给字符串常量。
采用new关键字新建一个字符串对象
采用new关键字新建一个字符串对象时,JVM首先在字符串常量池中查找有没有"aaa"这个字符串对象,如果有,则不在池中再去创建"aaa"这个对象了,直接在堆中创建一个"aaa"字符串对象,然后将堆中的这个"aaa"对象的地址返回赋给引用str1,这样,str1就指向了堆中创建的这个"aaa"字符串对象;如果没有,则首先在字符串常量池池中创建一个"aaa"字符串对象,然后再在堆中创建一个"aaa"字符串对象,然后将堆中这个"aaa"字符串对象的地址返回赋给str1引用,这样,str1指向了堆中创建的这个"aaa"字符串对象。
14、String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
15、Files的常用方法都有哪些?
Files.exists():检测文件路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。
什么是热部署?
热部署原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后再启动更快。
16、StringUtils常用的方法
判空:isNonBlank、isBlank
17、Tomcat重启
查看tomcat
ps -ef|grep tomcat_inmanage
结果:
eloan 1224 1161 0 18:22 pts/7 00:00:00 grep --color=auto tomcat_inmanage
eloan 28845 1 5 Feb26 ? 08:53:35 /usr/local/jdk/bin/java
杀进程:
kill 9 28845
启动tomcat
startting tomcat
18、字符串常量池
字符串常量池又称为:字符串池,全局字符串池,英文也叫String Pool。 JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间---字符串常量池。字符串常量池由String类私有的维护。
优缺点
字符串常量池的优点:避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;
字符串池的缺点:牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。
19、浅拷贝和深拷贝的区别
浅拷贝: 只复制当前对象的基本数据类型及引用变量,没有复制引用变量指向的实际对象。修改克隆对象可能影响原对象,不安全。
深拷贝: 完全拷贝基本数据类型和引用数据类型,安全。
20、自动装箱/拆箱是什么
每个基本数据类型都对应一个包装类,除了 int 和 char 对应 Integer 和 Character 外,其余基本数据类型的包装类都是首字母大写即可。
自动装箱: 将基本数据类型包装为一个包装类对象,例如向一个泛型为 Integer 的集合添加 int 元素。
自动拆箱: 将一个包装类对象转换为一个基本数据类型,例如将一个包装类对象赋值给一个基本数据类型的变量。
注意:
比较两个包装类数值要用 equals ,而不能用 == 。
21、哪个类是所有类的超类?
java.lang.Object 是所有 Java 类的超类,我们不需要继承它,因为是隐式继承的。
22、finally 和 finalize 有什么区别?
finally 通常与 try-catch 块一起使用,即使 try-catch 块引发了异常,finally 块中的代码也会被执行,用于释放 try 块中创建的资源。
finalize() 是 Object 类的一个特殊方法,当对象正在被垃圾回收时,垃圾收集器将会调用该方法。可以重写该方法用于释放系统资源。
23、可以将一个类声明为 static 的吗?
不能将一个外部类声明为 static 的,但可以将一个内部类声明为 static 的——称为静态内部类。
外部类:
内部类:
24、try–catch-finally
public class Trycatchfinally {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/牛逼.txt"));
String str = null;
while ((str =br.readLine()) != null) {
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
25、抽象类和接口有什么区别?
声明抽象类的关键字为 abstract,声明接口的关键字为 interface。
抽象类可以有具体的方法,接口不能。
一个类只能继承一个抽象类,但可以实现多个接口。
接口中的变量只能是隐式的常量,抽象类中可以有任意类型的变量。
如果一个抽象类有 main() 方法,则可以运行它;但接口不能。
抽象类是对类的一种抽象,继承抽象类的类和抽象类本身是一种 is-a 的关系。
接口是对类的某种行为的一种抽象,接口和类之间并没有很强的关联关系,所有的类都可以实现 Serializable 接口,从而具有序列化的功能。
26、什么是枚举?
enum(枚举)是 Java 1.5 时引入的关键字,它表示一种特殊类型的类,默认继承自 java.lang.Enum。
enum 是用于创建枚举的关键字,枚举中的常量都是隐式 static 和 final 的。
- 要使用“==”运算符来比较两个枚举是否相等。
- 因为“==”运算符比较的时候,如果两个对象都为 null,并不会发生 NullPointerException,而 equals() 方法则会;另外, “==”运算符会在编译时进行检查,如果两侧的类型不匹配,会提示错误,而 equals() 方法则不会。
EnumSet
EnumSet 是一个专门针对枚举类型的 Set 接口的实现类,它是处理枚举类型数据的一把利器,非常高效。
因为 EnumSet 是一个抽象类,所以创建 EnumSet 时不能使用 new 关键字。不过,EnumSet 提供了很多有用的静态工厂方法:
EnumMap
EnumMap 是一个专门针对枚举类型的 Map 接口的实现类,它可以将枚举常量作为键来使用。EnumMap 的效率比 HashMap 还要高,可以直接通过数组下标(枚举的 ordinal 值)访问到元素。
和 EnumSet 不同,EnumMap 不是一个抽象类,所以创建 EnumMap 时可以使用 new 关键字:
EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);
27、什么是序列化和反序列化?
我们可以把一个 Java 对象转化成一个数据流,这被称为序列化。一旦对象被转化为数据流后,就可以将其保存到文件或者通过网络套接字发送。
如果一个对象实现了 Serializable 接口,就可以使用 java.io.ObjectOutputStream 将对象写入文件。
将数据流再转化为 Java 对象被称为反序列化。
28、什么是 instanceof 关键字?
可以使用 instanceof 关键字检查对象是否属于一个类。
if(str instanceof Integer){
………
}
29、堆(heap)和栈(stack)有什么区别?
- 堆内存被应用程序的所有部分使用,而栈内存仅由执行线程使用。
- 当我们创建对象时,它始终存储在堆空间上;栈仅存储该对象的引用,栈内存还可以存储局部的基本类型数据变量。
栈的内存管理方式是 LIFO(后进先出)形式,而堆的内存管理方式更复杂。
30、连接数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class main {
public static void main(String[] args) {
//声明Connection对象
Connection con;
//驱动程序名
String driver = "com.mysql.jdbc.Driver";
//URL指向要访问的数据库名mydata
String url = "jdbc:mysql://localhost:3306/sqltestdb";
//MySQL配置时的用户名
String user = "root";
//MySQL配置时的密码
String password = "123456";
//遍历查询结果集
try {
//加载驱动程序
Class.forName(driver);
//1.getConnection()方法,连接MySQL数据库!!
con = DriverManager.getConnection(url,user,password);
if(!con.isClosed())
System.out.println("Succeeded connecting to the Database!");
//2.创建statement类对象,用来执行SQL语句!!
Statement statement = con.createStatement();
//要执行的SQL语句
String sql = "select * from emp";
//3.ResultSet类,用来存放获取的结果集!!
ResultSet rs = statement.executeQuery(sql);
while(rs.next()){
//获取stuname这列数据
job = rs.getString("job");
//获取stuid这列数据
id = rs.getString("ename");
//输出结果
System.out.println(id + "\t" + job);
}
rs.close();
con.close();
} catch(ClassNotFoundException e) {
//数据库驱动类异常处理
System.out.println("Sorry,can`t find the Driver!");
e.printStackTrace();
} catch(SQLException e) {
//数据库连接失败异常处理
e.printStackTrace();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
System.out.println("数据库数据成功获取!!");
}
}
}
31、外部类和内部类
内部类分为成员内部类,匿名内部类、局部内部类和静态内部类。
成员内部类
定义在一个类的内部:
public class MemInner {
int num = 10;
public static void main(String[] args) {
MemInner mi = new MemInner();
Inner in = mi.new Inner();
System.out.println(in.num);
in.systemOut();
}
public class Inner{
int num = 9;
public void systemOut(){
System.out.println(num);
System.out.println(MemInner.this.num);
}
}
}
如果外部类想要调用内部类,先要实例化内部类相对的外部类,然后再实例化目标内部类,然后才能访问里面的成员变量和方法。
并且如果想要访问内部类和外部类同名的成员变量或成员方法,需要按照以下格式访问:
外部类.this.成员变量
外部类.this.成员方法
而且无论外部类的成员变量或成员方法的访问权限是什么,内部类统统都可以访问。
局部内部类
public class AreaInner {
int num = 9;
public static void main(String[] args) {
AreaInner ai = new AreaInner();
ai.Inner();
}
public void Inner(){
String name = "黄花大闺女";
class AInner{
void call(){
System.out.println(num);
System.out.println(name);
}
}
AInner an = new AInner();
an.call();
}
}
就像是main()函数调用不了方法中的局部变量一样,如果想要在外部类实例化局部内部类,首先要在这个方法或者作用域里面提前实例化此内部类,然后在外部类调用其方法或者作用域的时候,就可以真正为这个内部类提供资源空间。
匿名内部类
匿名内部类在用作监听器的时候是一个非常方便的写法,而且匿名内部类有两个特点:无构造器,不可使用static等限定词。
buttons[0].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
});
使用匿名内部类之后就不需要在外部类重新实例化了,方便好用。
静态内部类
静态内部类跟成员内部类的区别就在于有没有"static"修饰,然后因为是静态类,所以要能访问的只有外部类中被static修饰过的成员变量或者方法。
public class StaticInner {
int num = 9;
static String name = "黄花大闺女";
Inner i = new Inner();
static class Inner{
void call(){
System.out.println(num); //会报错
System.out.println(name);
}
}
}
在没有外部类的情况下是可以直接创建静态内部类实例的,但是如果要使用外部类的非静态成员变量或成员方法,还是需要创建外部类实例才可以使用。