JavaOOP
1、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1; 有错吗?
解答:
-
short s1 = 1; s1 = s1 + 1; **错误!**根据java的基本数据类型转换规则,s1为short类型的变量,在表达式s1 = s1 + 1中,s1会自动转换为int类型与整数1进行运算,结果自然为int型,而int型赋值给short型需要强制转换。
-
short s1 = 1; s1 += 1; 正确!在复合赋值运算符底层自动进行强制类型转换,所以此处实际是s1 = (int)s1 + 1; 因为这里进行了强制类型转换,所以编译可以通过。
知识点:java的基本类型转换
-
自动类型转换:小–>大
byte-->short-->int-->long-->float-->double
-
强制类型转换:大–>小
小类型 变量名 = (大类型) 值
值得注意的是:自增/自减运算符、复合赋值运算符底层做了优化,内部自动强制类型转换;
如:
++,--,+=,-=,......
-
类型提升:是指在多种不同数据类型的表达式中,类型会自动向范围表达大的值的数据类型提升;
long count = 999;
int unitPrice = 9;
long totalPrice = price * count;
2、重载与重写的区别
首先重载与重写都是指方法的重写与重载,都是实现多态的方式,但是方法的重载实现的是编译时的多态性,
而方法的重写实现的是运行时的多态性。
重载:(两同一不同)
- 同一个类中,方法名相同
- 参数列表不同,即参数类型或者个数不相同
- 发生在同一个类中
- 方法的返回值类型、修饰符可同可不同
- 重载常见的例子:类的构造函数
- 一个方法可以被重载多次
重写:
- 返回值、方法名、参数都相同
- 发生在父类与子类之间,也叫子类的方法覆盖父类的方法
- 子类方法的访问级别不能低于父类相应方法的访问级别
- 父类的方法只能被子类覆盖一次
3、数组实例化有几种方式?
public class arrayTest {
public static void main(String[] args) {
//第一种 动态实例化 实例化数组的时候,只指定了数组长度,数组中所有元素都是数组类型的默认值
String[] test1 = new String[6];//声明时指定长度
test1[0] = "数组0";//然后赋值
test1[1] = "数组1";
//第二种 静态实例化 创建数组时指定初始值
String[] test2 = {"数组0","数组1","数组2","...."};
//静态实例化
String[] test3 = new String[]{"数组0","数组1","数组2","...."};
}
}
4、Java中各种数据默认值
- Byte,short,int,long默认都是0
- Boolean默认值是false
- char默认值是 ‘\u0000’与0,’\u0000’是Unicode码的字符,每一个’\u0000’代表一个空格
- float,double默认值是0.0
- 对象类型默认值是null
5、Object类常用方法有哪些?
equals() 判断
hashCode() 返回对象的哈希码值
toString() 返回此对象的字符串表示形式
wait() 导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法
notify() 唤醒正在等待对象监听器的单个进程
clone() 创建并返回此对象的副本
getClass() 返回object的运行类
6、java是值传递还是引用传递?
解答:java是值传递,只是
- 对于基本数据类型,传递的是基本数据类型的量值的拷贝
- 对于引用类型,传递的是该引用所指向的对象在内存中的地址值的拷贝
知识点1:实参和形参
//形参:在定义函数时使用的参数
public static void test(String param){ // param为形参
System.out.println(param);
}
//实参:函数在调用其他函数时,在被调用函数后面的括号中的参数为实参
public static void main(String[] args) {
test("argument");//“argument” 为实参
}
知识点2:值传递与引用传递
- 值传递:在调用函数的时候,将实参复制一份之后传递到函数中,在函数中对参数修改,不会修改到实参
- 引用传递:在调用函数的时候,将实参的地址传到函数中,函数中的修改会改变实参
总结:是否为值传递,关键判断是否会创建副本(不论是对基本数据类型中的变量创建副本,还是对引用类型中对象的地址创建副本),只要创建了副本就是值传递。
int a = 1;
a = 2;
System.out.println("============="+a); // 2
String str = "wuwuwu";
str = "hahaha";
System.out.println("***************"+str); // hahahaha
7、形参与实参的区别
形参:
- 形式参数,又称虚拟变量
- 定义函数名和函数体的时候使用参数,目的是用来接收调用该函数时传入的参数
- 形参本质是一个名字,不占用内存空间
实参:
- 在调用有参函数时,函数名后面括号中的参数为实际参数
- 可以是常量、变量或表达式,无论实参是何种类型,在进行函数调用时,都必须具有确定的值,以便把这些值传送给形参
- 在调用函数过程中,系统会把实参的值传递给被调用函数的形参。或者说,形参从实参得到一个值,该值在函数调用期间有效,可以参加该函数中的运算。
8、构造方法能不能重写?能不能重载?
解答:可以重载,不能重写
9、内部类与静态内部类的区别?
内部类:(inner class)
- 内部类中的变量和方法不能声明为静态的
- 内部类实例化:B是A的内部类,实例化B:
A.B b = new A().new B()
- 内部类可以引用外部类的静态或者非静态属性及方法
- 内部类需要持有对外部类的引用
静态内部类:(static nested class)
- 静态内部类属性和方法可以声明为静态的或者非静态的
- 静态内部类不依赖于外部类的实例,直接实例化,实例化静态内部类:B是A的静态内部类,
A.B b = new A.B()
- 静态内部类只能引用外部类的静态的属性及方法,不能引用外部类的非静态属性及方法
- 静态内部类不需要有指向外部类的引用,相对于外部类是独立存在的
10、static关键字有什么作用?
两种作用:
- 为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关
- 实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。
static主要有四种情况:
- 成员变量
- 成员方法
- 代码块
- 内部类
11、final在java中的作用,有哪些方法?
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写,JVM会尝试将其内联,以提高运行效率
- 被final修饰的变量不可以被改变,如果修饰引用,那么表示引用不可变,引用指向的内容可变
- 被final修饰的常量,在编译阶段会存入常量池中
12、String str=“aaa”, 与 String str = new String(“aaa”)一样吗?
13、java中的math类有哪些常用的方法?
Round():四舍五入
Abs():求绝对值
Random():生成一个0-1的随机数,包括0但不包括1
Sqrt():平方根
14、char 类型能不能转成 int 类型?能不能转成 string 类型? 能否转成 double 类型?
char类型可以隐式转换为int、double类型,但是不能转换为string类型
15、什么是拆装箱?
- **装箱:**就是自动将基本数据类型转换为包装器(int—>Integer)
调用方法:Integer.valueOf(int)方法
- **拆箱:**就是自动把包装器类型转换未基本数据类型(Integer—>int)
调用方法:Integer.intValue方法
注意:在新的jdk中,jvm会帮助我们进行拆装箱
16、java 中的包装类都是哪些?
byte: Byte
short: Short
int: Integer
long: Long
float: Float
double: Double
char: Character
boolean: Boolean
17、一个java类中包含哪些内容?普通类与抽象类有什么区别?
属性、方法、内部类、构造类、代码块
18、针对浮点型数据运算出现的误差的问题,如何解决?
使用BigDecimal类进行浮点数据的运算
19、面向对象的特征有哪些方面?
- **封装:**目的在于实现程序的"高内聚,低耦合",防止程序相互依赖而带来的变动影响。封装是把对同一事物进行操作的方法和相关方法放在同一个类中,把方法及其操作的数据放在同一个类中
- **抽象:**抽象就是找出事物的相似和共性,然后将这些事物归为同一类,这个类只考虑当前事物的相似和共性,忽略和当前业务不相关的因素
- **继承:**子类继承父类的方法作为自己的方法,可以加入新的方法或者是修改父类的方法体与业务需求更加贴合,提高小程序的可重用性和可扩张性
- **多态:**多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
20、访问修饰符 public,private,protected,以及不写(默认)时的区别?
修饰符 | 当前类 | 同包 | 子类 | 其他包 |
---|---|---|---|---|
public | 能 | 能 | 能 | 能 |
protected | 能 | 能 | 能 | 不能 |
default | 能 | 能 | 不能 | 不能 |
private | 能 | 不能 | 不能 | 不能 |
21、什么是接口?为什么需要接口?接口有哪些特点?
接口就是某个方法对外提供的一些功能的声明,是一种特殊的java类,接口弥补了java单继承的缺点
22、抽象类和接口的区别?接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?
抽象类是否可继承具体类(concreteclass)?
23、hashCode 的作用
解答:hashCode的作用需要从java集合说起,java中的集合(Collection)可以分为两大类 List 和 Set ,List中的元素是有序可重复的,Set中的元素是无序不可重复的;那么这里就会存在元素是否重复这个冲突问题,在集合中新增元素时,就需要调用Object.equals()方法,但是如果每增加一个元素,就要调用一次equals方法,元素很多的情况下,效率很低,于是,java采用了哈希表的原理,哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上的,hashCode方法实际上返回的就是对象存储的物理地址(暂且这么理解),这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,便可以直接定位到该元素应该放置的物理位置上,如果这个位置上没有元素,它就可以直接存储到这个位置上,不用进行任何比较了;如果这个位置上已经有元素了,则调用equals方法与新元素进行比较,相同的话就不存了,不相同就散列其他的地址。这样可以大大提高效率了。
- hashCode的存在主要用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;
- 如果两个对象相同,就是适用于equals(Java.lang.Object)方法,那么这两个对象的hashCode一定相同;
- 如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上述第二条;
- 两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object)方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”
24、深拷贝与浅拷贝的区别是什么?
知识点1:数据类型
基本数据类型特点:直接存储在栈stack中的数据
引用数据类型的特点:存储的是该对象在栈中引用,即在栈中存储了指针,真实的数据存放在堆内存中
知识点2:浅拷贝与深拷贝
- 深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的
- 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,
- 深拷贝会另外创造一个一模一样的对象,新对象跟旧对象不共享内存,修改新对象不会更改就对象
25、JDBC操作的步骤
- 配置JDBC所需的四个参数(user,password,url,driverClass)
//url 定义了连接数据库时的协议,子协议,数据源标识,他们直接用冒号隔开
//Mysql的连接URL
jdbc:mysql://localhost:3306/database_name?useUnicode=true&characterEncoding=gbk ;
//协议:在JDBC中总是以jdbc开始
//子协议:是桥连接的驱动程序或是数据库管理系统名称
//数据源标识:标记找到数据库来源的地址与连接端口
useUnicode=true:表示使用Unicode字符集。
如果characterEncoding设置为gb2312或GBK,本参数必须设置为true 。
characterEncoding=gbk:字符编码方式。
- 加载JDBC驱动程序
// 在连接数据库之前,首先要加载想要连接的数据库驱动到JVM(java虚拟机),这通过java.lang.Class类的静态方法 forName(String className)实现
try{//加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver") ;
}catch(ClassNotFoundException e){
System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace() ;
}
//成功加载后,会将Driver类的实例注册到DriverManager类中
- 创建数据库的连接
//连接MySql数据库,用户名和密码都是root
//要连接数据库,需要向java.sql.DriverManger请求并获得Connection对象,该对象就代表一个数据库的连接;
String url = "jdbc:mysql://localhost:3306/test" ;
String username = "root" ;
String password = "root" ;
try{
//使用DriverManger的个体Connection(String url,String username,String password)方法传入指定的数据库的路径、用户名和密码
Connection con = DriverManager.getConnection(url , username , password ) ;
}catch(SQLException se){
System.out.println("数据库连接失败!");
se.printStackTrace() ;
}
- 创建一个preparedStatement
//要执行SQL语句,必须获得java.sql.Statement实例,Statement实例有三种
//第一种 执行静态SQL语句
Statement stmt = con.createStatement() ;
//第二种 执行动态SQSL语句
PreparedStatement pstmt = con.prepareStatement(sql) ;
//第三种 执行数据库存储过程
CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}") ;
- 执行SQL语句
//Statement接口提供了三种执行SQL语句的方法
//第一种 执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;
//第二种 用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句如CREATE TABLE 和 DROP TABLE
int rows = stmt.executeUpdate("INSERT INTO ...") ;
//用于执行返回多个结果集、多个更新计数或二者组合的语句
boolean flag = stmt.execute(String sql) ;
- 遍历结果集
//ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
//使用结果集(ResultSet)对象的访问方法获取数据:
//列是从左到右编号的,并且从列1开始
while(rs.next()){
String name = rs.getString("name") ;
String pass = rs.getString(1) ; // 此方法比较高效
}
- 处理异常,关闭JDBC对象资源
//操作完成后要把所使用的JDBC对象全都关闭,以释放JDBC资源
//关闭顺序和声明顺序相反
if(rs !=null){ // 先关闭requestSet记录集
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt !=null){ // 再关闭preparedStatement声明
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn !=null){ // 最后关闭连接对象connection
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
26、什么时候使用 assert
断言在软件开发中是一种常用的调试方式,很多开发语言都支持这种机制,一般来说,断言用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。
assert关键字语法:有两种
-
assert <boolean表达式>
如果<boolean表达式>为true,则程序继续执行。
如果为false,则程序抛出AssertionError,并终止执行。
-
assert <boolean表达式> : <错误信息表达式>
如果<boolean表达式>为true,则程序继续执行。
如果为false,则程序抛出java.lang.AssertionError,并输入<错误信息表达式>。
assert陷阱:
- assert关键字需要在运行时候显式开启才能生效,否则你的断言就没有任何意义。而现在主流的Java IDE工具默认都没有开启-ea断言检查功能。这就意味着你如果使用IDE工具编码,调试运行时候会有一定的麻烦。并且,对于Java Web应用,程序代码都是部署在容器里面,你没法直接去控制程序的运行,如果一定要开启-ea的开关,则需要更改Web容器的运行配置参数。这对程序的移植和部署都带来很大的不便。
- 用assert代替if是陷阱之二。assert的判断和if语句差不多,但两者的作用有着本质的区别:assert关键字本意上是为测试调试程序时使用的,但如果不小心用assert来控制了程序的业务流程,那在测试调试结束后去掉assert关键字就意味着修改了程序的正常的逻辑。
- assert断言失败将面临程序的退出。这在一个生产环境下的应用是绝不能容忍的。一般都是通过异常处理来解决程序中潜在的错误。但是使用断言就很危险,一旦失败系统就挂了。
27、String、StringBuilder、StringBuffer的区别?
- String表示内容不可修改的字符串,覆盖了equals()和hashcode()方法
- StringBuffer表示内容可以修改的字符串,未覆盖上述两个方法,所以存储到java集合类时会出现问题
- StringBuilder也表示内容可以修改的字符串,但是其线程不安全,运行效率高
28、数组有length()方法吗?String尼?
- 数组没有length()这个方法,但是有length属性去计算数组长度
- String有length()方法计算字符串长度
29、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
- 一个java源文件中可以定义多个类,但是最多只有一个类被public修饰,并且这个类的类名与文件名必须相同。每个编译单元(文件)都只能有一个public类,这表示,每个编译单元都有单一的公共接口,用public类来表现。该接口可以按要求包含众多的支持包访问权限的类。如果在某个编译单元内有一个以上的public类,编译器就会给出错误信息。
- 若这个文件中没有public类,则文件名可随便命名(前提是符合规范)
- 值得注意的是,当用javac指令编译有多个类的java源文件时,它会给该源文件中的每个类生成一个对应的.class文件
30、用最有效率的方法算出2乘以8等于几?
2<<3 位运算 左移三位
因为将一个数左移n位,就相当于乘以2的n次方,那么,一个数乘以8只要将其左移三位即可,而位运算cpu直接支持的,效率最高。