Java基础 面试题

一、概述

JVM、JRE、JDK的区别

  • JVM:Java虚拟机
  • JRE:Java虚拟机 + Java程序核心类库(lang包等)
  • JDK:JRE + Java开发工具(编译工具,打包工具等)

跨平台原理

JAVA程序是通过Java虚拟机在系统平台上运行的,Java源代码经过虚拟机编译后成字节码文件(.class),他不面向任何特定的处理器,只面向虚拟机

Java程序的主类

一个程序可以很多类,但是只能有一个主类,在Java应用程序中,这个主类是指包含main方法的类,而在小程序中,这个主类是一个继承自japplet或Applet的子类,应用程序的主类不一定要求是public类

Java应用程序与小程序的区别

Java应用程序通过主线程启动,applet小程序没有main方法,主要是嵌在浏览器页面行运行,通过init线程或run来启动

二、基础概念

数据类型

Java是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了大小不同的空间

分类

  1. 基本数据类型
    整型:byte(1字节)、short(2)、int(4)、long(8)
    浮点型:float(4)、double(8)
    字符型:char(2)
    布尔型:boolean(1)

1字节 = 8位,在计算机系统中,一个0或者1占一位的存储空间

  1. 引用数据类型
    数组、类、接口

其他

  • long不可以作用在Switch上

Java12中引入了对long的支持,也就是说,Java12以后就可以了

  • 最效率的计算方法:位运算,2<<3; 左移3位相当于乘以2的三次方,右移3位相当于除以2的三次方
  • 高精度赋值给低精度,属于窄化,会造成精度损失
  • += 进行了隐式地强制类型转换;short i += 1 -> i = (short)i + 1;

访问修饰符

  • public:公共,对所有包所有类可见,可用于:类、接口、属性、方法
  • protected:受保护的,对同一包内的类及子类可见,可用于:属性、方法,不能修饰类
  • default:缺省,同一包内可见,但不包括子类,可用于:类、接口、属性、方法
  • private:私有,同一类可见,不包括子类,可用于:方法、属性,不能修饰类

运算符

  • &与&&,|与||:&是逻辑与,要求运算符两边都是TRUE,结果才位TRUE;&&是短路与,同样要求运算符两边都是TRUE,但是,如果运算符的左边为FALSE,那么表达式就会被直接短路,不会在继续计算右面的表达式,|与||同理

关键字

  • final:用于修饰类和方法及属性;修饰类:此类不可继承、修饰方法:此方法不可重写、修饰属性:此属性不可再被赋值(不可再改变属性的引用,而不是引用指向的内容,引用指向的内容可以改变)
  • finally:通常用在try - catch 代码块中,表示不管是否出现异常,这个代码块都会被执行,通常用于关闭某些需要手动关闭的资源
  • finalize:这是一个方法,属于object类,一般由垃圾回收器来调用,当我们调用system . gc ( ) 方法时,由垃圾回收器调用finalize回收垃圾,一个对象是否可回收的最后判断yan

流程控制语句

  • break:跳出循环
  • continue:跳出本次循环
  • return:结束方法
  • 跳出多重循环:在循环体外加入标号(标号 :),使用break 标号;即可跳出外层循环

三、面向对象

三大特性

  • 封装
  • 继承:子类拥有父类的非private属性和方法
  • 多态:程序中定义的引用变量所指向的具体类型(可能是父类子类)和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例,该引用变量发出的方法调用哪个类中实现的方法,必须在程序运行期间才能决定;实现多态的两种方式:继承和接口

类与接口

抽象类与接口

  • 抽象类用于捕捉子类的通用特性,而接口用于规范实现类的行为

共同点:

  1. 接口和抽象类都不能实例化
  2. 都位于继承的顶端,用于被其他类继承或者实现
  3. 都包含抽象方法,其子类需要重写这些方法

抽象类的子类如果没有实现这些抽象方法,那么它本身也必须声明为一个抽象类,否则就必须实现父类抽象类所有的抽象方法
在Java8中,接口引入了默认方法,可以在接口中提供具体的实现,而子类不需要实现这些方法,让接口更加灵活,这是接口演化的结果,在这之前,一个接口被定义好以后,如果要添加新的方法,那么它所有的实现类都需要也增加对应的方法,引入默认方法后,实现类就可以有选择地实现这些方法

区别:

  1. 其实现的关键字不同:继承:extends,实现:implement
  2. 其声明的关键字不同:抽象类:abstract,接口:interface
  3. 构造器:抽象类可以有构造器,接口没有

抽象类中构造方法有两个作用:

  1. 初始化抽象类的成员变量
  2. 实现类在实例化的时候需要调用父类的构造方法进行初始化工作,因为子类继承了父类的属性和方法,需要确保父类的成员变量得到了正确的初始化
  • 一个类如果没有显式地声明构造方法,那么Java会提供一个无参的构造方法,当子类初始化的时候,如果没有显式地调用父类的构造方法,那么就会隐式地调用父类的无参构造方法,但是如果父类只有有参构造方法,那么子类在初始化的时候,必须显式地调用父类的有参构造方法,并传入对应的参数,否则会编译报错
  1. 访问修饰符:抽象类中的方法:随意,接口中的方法:不允许private或者protected
  2. 一个类只能继承一个抽象类,但是可以实现多个接口
  3. 抽象类的属性可以用任意的修饰符,但是接口的属性都是public、static和final的,也就是静态常量

普通类与抽象类的区别

  • 普通类不能包含抽象方法
  • 抽象类不能直接实例化
  • 抽象类不能用final来修饰,因为它声明出来就是用来给其他类继承的

变量与方法

1. 成员变量与局部变量

  • 成员变量:定义在方法外,作用域是整个类,随对象的创建与销毁而创建于销毁,存储在堆内存,默认是有初始值的
  • 局部变量:定义在方法内,作用域只在方法,随语句执行的结束而结束,存储在栈内存,默认无初始值,使用前需赋值

2. 无参构造的作用

  • Java程序在执行子类的构造方法前,如果没有通过super()来调用父类特定的构造方法,那么就会默认调用父类中的无参构造。

3. 构造函数

  • 作用:帮助完成对类对象的初始化工作,一个类没有显式声明构造函数的时候,也会有默认的无参构造

  • 特征:

    • 方法名与类名相同
    • 无返回值,但是不能使用void声明
    • 生成类的对象时自动执行,无需调用

4. 静态变量与实例变量的区别

  • 静态变量:不属于任何对象,属于类,所以在内存中只有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间
  • 实例变量:每次创建对象,都会给每个对象分配成员变量的内存,实例变量属于实例对象,在内存中,创建多少个对象,就有几份成员变量

内部类

  • 内部类可以分为四种:
  1. 成员内部类:定义在类内部的非静态类;创建方式:外部类实例 . new 内部类()
  2. 局部内部类:定义在方法内的非静态内部类;创建方式:new 内部类()
  3. 局部内部类:定义在方法内的非静态内部类;创建方式:new 内部类()
  4. 静态内部类:定义在类内部的静态类;创建方式:new 外部类 . 静态内部类()

重载与重写

  1. 重载:同一类内,声明同名但是不同参数的方法(参数个数不同,类型或顺序不同),与方法的返回值和修饰符无关

这里的顺序不同,是在类型不同的前提下,比如说:
对于方法: add (int a, int b)
这样不属于重载:add (int b, int a)
在类型不同的时候,对于方法: add (int a, double b)
这样才属于重载:add (double b, int a)

  1. 重写:父子类之间,方法名与参数相同

重写时的访问修饰符和异常:
子类的访问修饰符范围不能比父类的访问修饰符小
子类抛出的异常范围不能比父类抛出的异常大

对象相等的判断

  1. == :比较基本数据类型:比较值;比较引用类型数据:比较内存地址
  2. equals:如果没有重写equals方法,用于比较对象的时候,等价与 == ;如果重写了equals,比较对象的时候,比较的是对象值(比较内容)

为什么重写了equals必须重写hashcode

  1. hashCode返回的哈希码用于在快速定位对象在哈希表等数据结构中的位置
  2. 重写了equals以后,两个具有相同内容的对象比较返回的值是true,也就是可以认定它们是同一个对象
  3. 如果没有重写hashCode,那它们返回的哈希码就不痛,就不在同一个位置,这违反了一致性原则

值传递

当一个对象被当做参数传递到一个方法后,可以在方法内修改这个对象的属性,那么这里是值传递还是引用传递?

值传递,Java语言的方法调用只支持值传递,方法只是得到了参数对象的拷贝,修改对象的拷贝并不会影响到对象本身

Java包

  • Java.lang
  • java.io
  • java.nio
  • java.net
  • java.net
  • java.net

io流

io流分几种

  • 根据流向:输入流、输出流
  • 根据操作单元:字节流、字符流
  • 根据角色划分:节点流、处理流

inputStream/Reader是所有输入流的基类,前者是字节输入流,后者是字符输入流

outputStream/writer是所有输出流的基类,前者是字节输出流,后者是字符输出流

BIO、NIO、AIO

  • BIO:block io,同步阻塞式io,并发处理能力低
  • NIO:non io,同步非阻塞式io,传统io的升级
  • AIO:异步非阻塞式io,NIO的升级

files的常用方法

  • files.exists:检测文件路径是否存在
  • fies.createFile:创建文件
  • files.createDirectory:创建文件夹
  • files.delete:删除文件
  • files.copy:复制文件

反射

  • 反射机制是指在运行状态中,对于任意一个类,都能知道这个类的所有方法和属性,对于任意一个对象,都能调用它的任意属性和方法,这种动态获取信息以及动态调用对象的方法的功能称为Java的反射机制

常用API

string

  • 字符型常量与字符串常量的区别:char与string

  • 字符串常量池
    位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串的时候,JVM会首先检查常量池,如果已经存在就返回它的引用,如果不存在就实例化一个字符串放到常量池中,并返回其引用

  • string的特性

  1. 不变性:string是只读字符串(final修饰的类,可以通过反射修改),对它进行的任何操作都是创建一个新的字符串,再把引用指向新字符串,这个特性的主要作用是,多线程操作时,可以保证数据的一致性
  2. 常量池优化
  3. 它是一个final修饰的char类型数组
  • 常用方法
  1. indexOf:返回指定字符的索引
  2. charAt:返回指定索引的字符
  3. replace:字符串替换
  4. trim:去除字符串两边的空白
  5. split:分割字符串,返回一个分割后的字符串数组
  6. getBytes:返回字符串的bytes类型数组
  7. getBytes:返回字符串的bytes类型数组
  8. substring:截取字符串
  9. equals:比较字符串
  • 使用hashmap的时候,用string做key的好处

hashMap需要通过key的hashcode来计算存储位置,因此字符串是不可变的,所以当创建了字符串以后,它的hashcode被缓存下来了,不需要经过再次计算

  • string、stringBuffer、stringBuilder
  1. stringBuffer与stringBuilder都继承自AbstractStringBuilder(定义了一些基本的字符串操作),它们都是可变的,而string不可变
  2. stringBuffer与stringBuilder都继承自AbstractStringBuilder(定义了一些基本的字符串操作),它们都是可变的,而string不可变
  3. string每次操作都会生成一个新的对象,而stringBuffer是对对象本身进行操作,所以性能更高
  4. 需要操作少量数据时使用string、需要单线程操作大量数据时使用stringBuilder、需要多线程操作大量数据时使用stringBuffer

包装类

  • 自动拆箱与自动装箱
  1. 装箱:将基本数据类型用它们对应的引用类型包装起来
  2. 拆箱:将包装类转换为基本数据类型
  • int 和 integer 的区别
  1. 引入包装类的原因:为了能将这些基本数据类型当成对象操作
  2. int 存储在常量池,integer存储在堆空间

整型字面量在-128 到 127之间,那么自动装箱时不会new新的integer对象,而是直接引用常量池的integer对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值