Java基础问题
基础问题
- 谈谈你对面向对象的理解 -- 结合场景
为何要使用对象编程?
可重复利用,方便拓展
面向对象有三大特征:封装、继承和多态
- 封装:为什么要封装?可以使类的成员(数据和行为)有选择性的暴露,这里面就有了四个不同的修饰符 -- private protected default public
- 继承: 提高代码的可重用性,往往都是子类继承父类中的成员;
- 多态: 主要目的是实现接口。通过 父类的引用指向子类的实例,来动态完成各个不同子类方法的调用。这里面就要涉及到重写和重载问题
- 重写 和 重载 的区别
作用范围不同:重载发生在同一个类中,重写发生在父子类中
对于一个函数来说:
重载
方法名必须相同,参数类型不同、个数不同、顺序不同;
返回值,可以不同;访问修饰符,可以不同
重写
方法名、参数列表必须相同 ;
返回值,范围要小于父类;访问修饰符,范围要大于父类,其中父类修饰符为private,子类就不能进行重写
- 泛型 generic
作用:通过在编译的时候能够检查类型安全(严格意义上是一种伪泛型)
什么时候用:
1、类、接口 -- 刷题倒是常用
2、方法 -- 来限定传入参数
static int countLegs (List<? extends Animal > animals ) {
int retVal = 0;
for ( Animal animal : animals )
{
retVal += animal.countLegs();
}
return retVal;
}
常用的通配符:
? 表示不确定的 java 类型
T (type) 表示具体的一个 java 类型
K V (key value) 分别代表 java 键值中的 Key Value
E (element) 代表 Element
- == 和 equals 的区别
这里就要提到Java中存在两种数据类型,基本数据类型 + 引用类型
== 在基本类型中,就是简单的进行数值比较,equals方法在基本类型中不存在
但是针对引用类型时,== 比较的 对象的地址值,Object 的 equals 方法就是比较对象的内存地址;因为所有的类都默认继承Object类,所以理论上这些类的equals方法都是进行地址值比较;
但一般常用的类,比如String,都将equals方法进行重写,主要比较的还是对象的内容
基本数据类型有几种? 6 + 2 数值型 + 字符 + 布尔(byte short int long float double character boolean)
- 为什么重写 equals 时必须重写 hashCode 方法?
hashCode()定义在 JDK 的 Object 类中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。
那么hashCode() 的作用是啥?主要还是应用在HashMap这种需要涉及到散列表的类中,通过它获取对象的散列码,我们判断两个对象是否相等,需要:
通过hashCode() 获得两个对象的散列码,在两者相同的基础上,再进行equals判断内容是否相等。
- Java中存在一个空参构造器干嘛?
构造器的作用:初始化对象。
在Java框架中,往往通过反射来创建对象,之后动态的向对象赋值
Student s = (Student)Class.forName("Student类全限定名").newInstance();
另外,在父子类中,实例化子类对象往往是一个递归过程,也就是说会先实例化父类对象,一直向上,最终是先实例化Object类,这就要求父类要存在一个无参构造器,都为有参构造器的话,子类无法利用super()来实例化父类,另外父类也参与了子类变量的初始化工作。
- 抽象类和接口的区别
变量 抽象类可以是各种类型的,接口只能是 public static final
方法 抽象类可以实现,接口中只能存在 public abstract 方法
静态代码块和静态方法,抽象类可以有,但是接口不可以包含
继承:一个类只能继承一个抽象类,却能实现多个接口
String问题
- 内存问题
String st1 = new String(“abc”);
Q:这句话在内存中创建了几个对象
A:在内存中创建两个对象,一个在堆内存,一个在常量池,堆内存对象是常量池对象的一个拷贝副本。new这个关键字,就要想到new出来的对象都是存储在堆内存,“abc”属于字符串,字符串属于常量,所以应该在常量池中创建。
String st1 = "abc";
String st2 = "abc";
System.out.println(st1 == st2); //true
System.out.println(st1.equals(st2)); //true
String st1 = new String("abc");
String st2 = "abc";
System.out.println(st1 == st2); //false (一个在堆,一个在常量池)
System.out.println(st1.equals(st2)); //true
- String与 StringBuilder、StringBuffer区别
String因为被声明为 final class,是不可变字符串。因为它的不可变性,所以拼接字符串时候会产生很多无用的中间对象;
StringBuffer 就是为了解决这个问题而提供的一个类。它设计之初是一个线程安全的可修改的字符序列,但在很多情况下我们的字符串拼接操作不需要线程安全,所以就有了StringBuilder 。StringBuilder 是 JDK1.5 发布的,它和 StringBuffer 本质上没什么区别,就是去掉保证线程安全的那部分,减少开销,提升性能。
Object类
1、clone() -- 复制一个对象并返回,是一种浅拷贝(单纯复制对象的引用)
2、equals()、toString() -- 重点 几乎每次都要重写
3、finalize() -- 对象被回收之前调用,交给Garbage Collector处理,自己不要用
4、getClass() -- 对象获取自己的类
5、hashCode() -- 集合章节
6、notify()、notifyAll()、wait() --多线程章节
深浅拷贝 -- Object拷贝方法是一种浅拷贝
- 值传递和引用传递有什么区别?
Java中参数传递是值传递
基本类型作为参数被传递时肯定是值传递;
引用类型作为参数被传递时也是值传递,只不过“值”为对应的引用。(对象本身发生变化,但是指向没有变)
- toString()
大部分的时候都需要进行重写
默认的形式为:
public String toString(){
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
//可以看出此处用到两个 Object的方法
static 与 final
static可以用来修饰类的方法、变量,修饰类,只能是内部类
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。可以在没有创建对象的情况下来进行调用(方法/变量)
主要看 修饰方法 、 变量
1、修饰方法,最典型的不就是main函数吗?
因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
public static void main(String[] args) {}
2、修饰变量
静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。
class MyClass {
public final double i = Math.random();
public static double j = Math.random();
}
//一旦类被加载后,j 的值就是一个确定的值,之后去访问它是不会变化其值的
//但是i 不同,创建不同实例,其值就随机变化一次
final关键字可以用来修饰类、方法和变量
当用final修饰类时,表明这个类不能被继承,典型的就是String
当final修饰方法时,被修饰的方法无法被所在类的子类重写(覆写),典型的就是Object类中的getClass()方法
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象(但是对象里面的值是可以改变的,比如final修饰数组)
这里就有了与static的区别,static final 经常组合出现,作为类常量使用
static 和 final的区别
- static修饰变量,表示在一个类中只保存一份副本(指向唯一),没说它值不可变;
所有由一个类创建的实例,它们的static变量都指向相同,就像createCarNum,不同实例都可以修改它,但内存中只有一个,存在【方法区】
- final修饰变量,保证在一个实例中变量值不可变,不同实例就不一定
不同实例,有不同的final变量,一旦确定就不能被修改。
可能会有疑惑,既然final变量要强制赋初值,那么不同实例不就是相同的值吗?反例请看:final double i = Math.random() 这个需要运行时才能确定
举例子:
Static修饰的createCarNum变量,一个类中只有一个指向,创建若干个CarFactory实例,能保证都只操作一个元素
public class CarConstants {
// 全局配置,一般全局配置会和final一起配合使用, 作为共享变量
public static final int MAX_CAR_NUM = 10000;
}
public class CarFactory {
// 计数器 -- 保证不管创建多少个实例都是这一个变量
private static int createCarNum = 0;
public static Car createCar() {
if (createCarNum > CarConstants.MAX_CAR_NUM) {
throw new RuntimeException("超出最大可生产数量");
}
Car c = new Car();
createCarNum++;
return c;
}
}
- 关键词比对:final、finally 和 finalize比较
final用于修饰属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承。
finally是异常处理语句结构中,表示总是执行的部分。
finallize表示是object类一个方法,在垃圾回收机制中执行的时候会调用被回收对象的方法。允许回收此前未回收的内存垃圾。所有object都继承了 finalize()方法
- 反射
反射可以说是框架的灵魂,使得我们在运行时分析类和执行类的方法。
通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
异常
- 异常分类
可以分为两个大类,Error 和 Exception,继承于 顶级父类 Throwable
Error,一般与虚拟机相关
分类:OOM(不断创建对象)、StackOverflow(递归)
Exception又分为:编译时异常、运行时异常
运行时异常
:不可预知,代码运行时,才可能知道
其中编译时异常
,必须在编写代码时,加入try-catch、throws(将可能的异常延迟到运行时出现),否则无法通过编译
//自己进行处理
public static void method1() {
try {
method();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//交给调用者来处理异常,调用者要不解决try-catch 或者再丢给上级
public static void method() throws FileNotFoundException{
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1) {
System.out.println((char)data);
data = fis.read();
}
fis.close();
}
- 你见过哪些异常?
编译时异常:IOException( -- FileNotFoundException)、ClassNotFoundException
运行时异常:NullPointerException、
ArrayIndexOutOfBoundsException、
ArithmeticException -- 算术异常(除0异常)、
NumberFormatException -- 将字符串转为数字、
ClassCastException -- 父子类强制转换。
- 异常处理机制
异常有两个过程
一、抛出异常,创建异常对象,交给运行时系统处理
二、处理异常:寻找合适的异常处理器处理异常,否则就终止运行
抛出异常:
① 系统自动生成的异常对象
② 手动生成一个异常对象,并抛出(throw)
处理异常:
① try-catch-finally -- 针对可能出现的异常,自己进行处理
② throws -- 丢给"上级"进行处理
"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型,由该方法的调用者来处理。
try-catch-finally:真正的将异常给处理掉了。throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。
try - catch - finally
try { //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容 }
catch { //除非try里面执行代码发生了异常,否则这里的代码不会执行 }
finally { //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally }
将 finally中的 return语句 注释掉
IO
- transient 关键字 -- 和序列化有关
一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
- 什么时候需要序列化? 怎么序列化?
当我们的对象需要跨平台存储和进行网络传输时,就考虑到序列化问题
Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程
/*
序列化步骤:
1、实现接口 Serializable
2、提供一个全局变量:serialVersionUID 序列版本号
注意: static和transient修饰的成员变量不能被序列化,其他默认可序列化
*/
- IO分类
流按照传输单位分为 字节流和字符流
字节流的抽象基类(父类)是:java.io.InputStream、java.io.OutputStream
字符流的抽象基类(父类)是:java.io.Reader 、 java.io.Writer
访问文件,存在字符文件(word)和二进制文件(音视频)
那么就存在两种文件流:
1、FileInputStream、FileOutputStream -- 字节
2、FileReader、FileWriter -- 字符!!(别记混了)
File file = new File("hello.txt");
FileReader fr = new FileReader(file);
//字符流 -- 可以合为一步
FileReader fr = new FileReader("hello.txt");
//字节流
File srcFile = new File(srcPath);
fis = new FileInputStream(srcFile);
为了加快传输速度,有了缓冲流,它的操作对象是 字节、字符流,而不是文件
BufferedInputStream ← FileInputStream 字节缓冲流
BufferedReader ← FileReader 字符缓冲流
BufferedReader(new FileReader(new File("hello.txt")));
BufferedInputStream(new FileInputStream(srcFile));
- Java的IO 和 NIO区别
NIO(即异步IO)和 经典IO(也就是常说的阻塞式(B)IO)
NIO主要有Channel、Buffer和Selector 三大核心组件
太难了orz~ 弃之
排序
排序名称 | 时间复杂度 | 空间复杂度 | 稳定 | 其他性质 |
---|---|---|---|---|
直接插入 | O(n^2) | O(1) | 稳定 | |
冒泡排序 | O(n^2) | O(1) | 稳定 | 能全局定位 |
快速排序 | O(nlogn) | O(logn) 递归需要栈 | 不稳定 | 能全局定位 |
选择排序 | O(n^2) | O(1) | 不稳定 | 能全局定位 |
堆排序 | O(nlogn) | O(1) | 不稳定 | 能全局定位 |
归并排序 | O(nlogn) | O(n) 需要等长的辅助表 | 稳定 |
- Java排序接口
存在两种方式,一种是Comparable的自然排序,另一个为Comparator的定制排序
//Comparable 接口 -- 一劳永逸
重写int CompareTo(Object o)方法
规则:当前对象this大于形参对象obj,则返回正整数
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods = (Goods) o;
if(this.price > goods.price){
return 1;
} else if(this.price < goods.price){
return -1;
}else{
return 0;
}
}
}
//Comparator -- 创建临时需要比较的规则
重写int compare(Object o1, Object o2) 方法
规则:o1大于o2,返回正
Arrays.sort(arr1, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2); //这里实现字符串逆序排序
}
}
});
Java基础问题的更多相关文章
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- 【JAVA面试题系列一】面试题总汇--JAVA基础部分
JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...
- 最适合作为Java基础面试题之Singleton模式
看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...
- java基础练习 字符串,控制流,日历,日期等
1,对基本控制流程的一些练习 package org.base.practice3; import org.junit.Test; /** * Created with IntelliJ IDEA. ...
- Java基础知识【下】( 转载)
http://blog.csdn.net/silentbalanceyh/article/details/4608360 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...
- Java基础知识【上】(转载)
http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...
- java基础学习03(java基础程序设计)
java基础程序设计 一.完成的目标 1. 掌握java中的数据类型划分 2. 8种基本数据类型的使用及数据类型转换 3. 位运算.运算符.表达式 4. 判断.循环语句的使用 5. break和con ...
- Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- java基础知识小总结【转】
java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...
随机推荐
- python测试框架-pytest
一.pytest 介绍.运行.参数化和数据驱动.Fixture pytest安装与介绍 官网 : pip install -U pytest 查看版本号:pytest --version 为何选择py ...
- 【刷题-LeetCode】306. Additive Number
Additive Number Additive number is a string whose digits can form additive sequence. A valid additiv ...
- 【解决了一个问题】腾讯云中使用ckafka生产消息时出现“kafka server: Message contents does not match its CRC.”错误
初始化的主要代码如下: config := sarama.NewConfig() config.Producer.RequiredAcks = sarama.WaitForAll // Wait fo ...
- 公司内部一次关于kafka消息队列消费积压故障复盘分享
背景现象 1.20晚上8点业务线开始切换LBS相关流量,在之后的1个小时时间内,积压量呈上升趋势,一路到达50W左右,第二天的图没贴出具体是50W数字,以下是第一天晚上的贴图部分. 现象一: 现象二: ...
- gin中模型的绑定和验证
要将请求体绑定到结构体中,使用模型绑定. Gin目前支持JSON.XML.YAML和标准表单值的绑定(foo=bar&boo=baz). Gin使用 go-playground/validat ...
- 开发者的瑞士军刀「GitHub 热点速览 v.22.04」
Swiss Army knife 可以说是本周的关键词了,多个项目采用该词来描述它的特性:像是能全方位解决浏览器"网络"操作的 CyberChef 方便你进行数据加密.解编码,还有 ...
- 深入了解promise
1. Promise基础 什么是回调地狱? 当使用回调函数来进行事件处理的时候,如果嵌套多层回调函数的时候,就会出现回调地狱,例如: method1(function(err, result) { i ...
- Vue3.2中的setup语法糖,保证你看的明明白白!
vue3.2 到底更新了什么? 根据原文内容的更新的内容主要有以下 5 块: 1.SSR:服务端渲染优化.@vue/server-renderer包加了一个ES模块创建, 与Node.js解耦,使在非 ...
- 解决matplotlib中文不显示问题
在导入库时添加如下几行代码 from pylab import mpl mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体 mpl.rcPa ...
- Vue3源码分析之 Ref 与 ReactiveEffect
Vue3中的响应式实现原理 完整 js版本简易源码 在最底部 ref 与 reactive 是Vue3中的两个定义响应式对象的API,其中reactive是通过 Proxy 来实现的,它返回对象的响应 ...