java基础(一)
文章参考的是javaGuide,https://snailclimb.gitee.io/javaguide/#/docs/java/basis/Java%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86
这里记录属于个人的查漏补缺,如果小伙伴需要更加全面和详细的资料,请看上面的链接呦!
1、java和c++的区别?
- 都是面向对象的语言,支持封装、继承和多态。
- java不指针来直接访问内存,程序内存更安全。并且java又自动的内存回收机制,不需要手动的释放内存
- java是单继承机制,但是接口可以实现多继承。c++支持多继承。
2、为什么说java语言“编译与解释并存”?
高级程序语言的执行方式有两种:编译型和解释型。
- 编译型:编译器针对特定的操作系统将源代码一次性翻译成可被该平台执行的机器码。
- 解释型:解释器对源程序进行解释成特定平台的机器码并立即执行。
java语言要先编译后解释两个步骤,java程序先经过编译生成.class文件,再有执行引擎来执行。
3、字符型常量和字符串常量的区别?
- 字符型常量是单引号‘’引起的一个字符;字符串常量是由双引号“”引起的0个或多个字符。
- 字符常量相当于一个整型值,可以参加表达式的运算;字符串常量代表一个地址值,即在内存中的存放位置。
- 字符常量占据2字节,字符串常量占据若干字节。
java中每种基本类型所占的空间大小是固定的,这也是它具有可移植性的原因之一。
4、标识符和关键字的区别是什么?
- 标识符:就是我们对java程序中的类、变量、方法等取得名字。有一些标识符比较特殊,在java中被指定了特殊大的含义,我们不可用,那就是关键字。
- 关键字:被赋予特殊含义的标识符。常见的关键字如下表:
5、continue、break、return的区别是什么?
当程序触发了某种条件之后,需要提前终止循环,这时候需要用到这几个关键字:
- continue:跳出当前的这一次循环,继续下一次循环
- break:跳出整个循环,执行循环下面的语句
- return:跳出所在的方法,结束该方法的运行。如果方法的返回值类型为void,就return;如果定义了其他类型,就 return value;
6、java泛型?什么是类型擦除,常用通配符有哪些?
泛型:是jdk5中引入的一个新特性,泛型提供了编译时类型安全检查机制,允许程序员在编译时检测到非法的类型。
好处:能够在编译时检查类型安全,所有的强制转换都是自动的和隐式的。
类型擦除: java的泛型是伪泛型,因为在编译期间,所有的泛型信息都会被擦掉,即类型擦除。
泛型常用的通配符为:T、E、K、V、?
- ?:表示不确定的java类型
- T (type):表示具体的一个java类型
- K V(key,value):键值对
- E(element):表示element
关于?和T的区别?
T 是一个确定的类型,通常用于泛型类和泛型方法的定义;
?是一个不确定的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法
// 可以
T t = operate();
// 不可以
? car = operate();
// 通过 T 来 确保 泛型参数的一致性
public <T extends Number> void
test(List<T> dest, List<T> src)
//通配符是 不确定的,所以这个方法不能保证两个 List 具有相同的元素类型
public void
test(List<? extends Number> dest, List<? extends Number> src)
class和class<?>的区别?
class在实例化的时候,必须要替换成具体类。
class<?>可以代表任何类。所以不知道声明什么类型的时候可以定义一个class<?>
public class Test{
public Class<?> test1;
public Class<T> test2; //报错
}
public class Test<T>{
public Class<?> test1;
public Class<T> test2; //不报错
}
7、==和equals的区别?
== :对于基本类型来说,比较的是值,对于引用类型来说,比较的是地址。比如string为引用类型,当创建string类型的对象时,虚拟机会在常量池中查找有没有已经创建过的对象的值和这个值相同,如果存在,就把它赋值给当前引用,不存在,就重新创建一个string对象。
equals :用来判断两个对象是否相等。所以它比较的是引用类型,不能用于比较基本类型。equals()方法有两种使用情况:
- 类没有覆盖equals()方法:等价于 == 比较这两个对象。
- 类覆盖了equals()方法:若是内容相等,返回true。
8、hashcode()和equals()
hashcode():确定该对象在哈希表中的索引位置。它被定义在object类中,代表java中的任何类都包含hashcode()函数。
比如在hashset判重的时候,会通过计算值的hashcode值来判断集合中是否存在该值,但是不同值的hashcode值可能相同,所以需要和equals方法一起来判断。当hashcode值相同时,equals方法返回true,说明这两个值是相同值。
重写equals()方法后,也必须重写hashcode()方法,不然就算是相同的内容,他们也不会相等。
9、为什么java中只有值传递?
各种程序语言中方法参数传递方式:
- 按值调用:方法接受的是调用者提供的值;一个方法不能修改传递值所对应的变量值。
- 按引用调用:方法接受的是调用者提供的变量地址;一个方法可以修改传递应用所对应的变量值。
java语言:
java语言总是按值调用,方法得到的是参数值的拷贝,所以他不能修改任何参数变量的内容。
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
//交换的是swap中拷贝的值,对于nums1和nums2本身没有任何影响
System.out.println("num1 = " + num1); //10
System.out.println("num2 = " + num2); //20
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a); //20
System.out.println("b = " + b); //10
}
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = new String("小张");
String s2 = new String("小李");
test.swap(s1, s2);
//方法并没有改变存储在s1和s2中的对象引用,而是改变了副本x,y的对象引用,所以对s1和s2没有影响。
System.out.println("s1:" + s1); //小张
System.out.println("s2:" + s2); //小李
}
public static void swap(String x, String y) {
String temp = x;
x = y;
y = temp;
System.out.println("x:" + x); //小李
System.out.println("y:" + y); //小张
}
}
10、重载和重写
-重载:发生在同一类中,方法名相同,参数类型和返回类型可能不同;
重写:发生在父子类中,方法名、参数名必须相同,重写发生在运行期,所以也是多态的一种表现形式。
方法的重写要遵守:“两同两小一大”
- 两同:方法名、参数类型相同
-两小:子类返回值类型 <= 父类返回值类型,子类声明方法抛出异常 <= 父类抛出异常 - 一大:子类方法的访问权限 >= 父类方法访问权限
11、深拷贝和浅拷贝
- 浅拷贝:基本类型进行值传递,引用类型进行引用类型般的拷贝;
- 深拷贝:基本类型进行值传递,引用类型,创建一个新对象,复制其内容;
12、面向对象和面向过程的区别
- 面向过程:性能高。单片机、嵌入式,linux等都是面向过程开发。面向对象中类的实例化开销较大。
- 面向对象:更容易维护、复用、和扩展。因为面向对象有封装、继承、多态的特性,可以设计出低耦合的系统。
面向过程性能比面向对象高?
因为java是半编译语言,他先转成字节码,然后由执行引擎转为二进制机器码。而面向过程大多是直接编译成机器码,所以性能相对高一点,但是也不是所有的面向过程的编程语言性能都比java好。
13、在java中定义一个无参构造方法的作用?
默认一个类都有一个隐式无参构造器,但是如果定了有参构造,就必须显示定义无参构造。吴如果没有无参构造的话,当这个类作为父类,其子类没有通过super()来调用父类中特定的构造方法,就会发生编译错误。
14、类的构造方法作用是什么?没有声明的话,程序能正常运行吗?
作用:完成对象的初始化工作。
没有声明构造方法也可以正常运行,因为一个类默认有个无参构造。所以new的时候会加一个(),因为要调用无参构造方法。
但是如果我们自己添加了类的构造方法(无论有参还是无参),java的这个默认无参构造就会失效。
构造方法的特性:
- 名字和类名相同
- 没有返回值,不能用void声明
- 生成类对象时自动执行,无需调用
15、面向对象的三大特性
-
封装:它是指将一个对象的属性隐藏在对象内部,提供一些方法供外界调用。就像空调里面的零件被装在空调里一样,我们通过遥控器来进行操作。
-
继承:在已经存在的类的基础上建立新类的技术,新类可以增加新的数据或者功能,也可以选择性继承父类。为了提高代码的复用,增强程序的可维护性。
-
多态:一个对象具有多种的状态,具体表现为父类的引用指向子类的实例。重写就是多态的体现。
16、静态方法和实例方法有什么不同?
- 调用静态方法不需要创建对象。所以可以使用“类名.方法名”和"对象名.方法名”来调用。实例方法需要实例化对象,所以只能通过“对象民.方法名”来调用。
- 静态方法在访问本类成员时,只能访问静态成员,不能访问实例成员变量和方法。因为静态方法是在类加载的时候初始化,且只加载一次,这时候类有可能还没被实例化,所以不可以i调用他的方法。实例方法没有限制。
17、接口和抽象类的区别?
接口:是对行为的抽象,是一种行为规范。所有的接口方法默认是public,接口中不能有实现。
抽象类:是对类的抽象,是一种模板。他的目的就是为了被重写,所以不能被private修饰。
因为java是单继承机制,所以一个类可以实现多个接口,但只能继承一个抽象类。
18、String、StringBuilder、StringBuffer
这个每次面试被问到,总觉得自己知道,但讲出来结果不尽如人意,再次整理一下。
他们都是用来定义字符串的。
- string是被final关键字修饰的,所以对象是不可变的,可以理解为是常量,线程安全。每次对string类型进行改变的时候,都会创建一个新对象,然后将指针指向新的string对象。
- StringBuilder和stringBuffer继承了AbstractStringBuilder类,stringbuffer类型进行改变的时候,是对对象本身进行操作,不会创建新的对象。StringBuilder对方法加了synchronized锁,所以是线程安全的,同时效率相比线程不安全的stringbuffer要低一点。
19、获取键盘输入的两种常见方法
- Scanner
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
- BufferedReader
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();
20、java的反射机制
反射是指在运行状态中,对于任意一个类都能知道这个类的属性和方法,对于任意一个对象,都能调用他的属性和方法。
优点:
运行期类型的判断,动态加载类,提高代码的灵活度。
缺点:
反射相当于一系列解释操作,通知jvm要做的事,性能比直接的Java代码要慢的多;而且还存在安全隐患。
21、java异常
所有的异常都继承于throwable类,有两个重要子类:exception和error。
- error是程序无法处理的错误。是代码运行时jvm的错误。
- exception时程序本身可以处理的异常。它包括runtimeException(受检异常(空指针异常、下标越界异常))和ioException(非受检异常)。
22、线程、进程、程序之间的关系
- 程序:含有指令和数据的文件,被存储在磁盘中,是静态的代码。
- 进程:程序的一次执行过程。是资源分配的最小单位。各进程之间运行是独立的,因为代表的是不同的应用程序。
- 线程:是cpu调度的基本单位。一个进程可以包含多个线程,他们共享一块内存空间和资源,所以有可能会出现竞争的情况。
23、java中的io流分为几种?
- 流的流向:输入流、输出流
- 操作单元:字节流(inputStream)、字符流(inputReader)
- 流的角色:节点流、处理流
24、为什么有字节流还要字符流?
不管是文件读写还是网络发送接受,信息的最小存储单位都是字节,那为什么还要分字符流呢?
字符流是由jvm将字节转换得到的,这个过程比较耗时,而且还有可能出现乱码问题。所以io流干脆提供一个直接操作字符的接口,方便对字符进行流操作。
25、BIO、AIO、BIO
- BIO:blocking io。同步阻塞io模式。数据的读写必须在一个线程内完成,适合连接数不多的情况。
- NIO:non-blocking io。同步非阻塞io模式。基于通道的io操作方法,使用于高负载、高并发的应用。
- AIO:asynchronous io。异步非阻塞io模式。基于事件和回调机制的,请求线程不会阻塞在哪里,可以继续作别的事,应用程序处理完之后,会通知线程继续后续的操作。