基础问题

  • 谈谈你对面向对象的理解 -- 结合场景

为何要使用对象编程?

可重复利用,方便拓展

面向对象有三大特征:封装、继承和多态

  1. 封装:为什么要封装?可以使类的成员(数据和行为)有选择性的暴露,这里面就有了四个不同的修饰符 -- private protected default public
  2. 继承: 提高代码的可重用性,往往都是子继承父中的成员;
  3. 多态: 主要目的是实现接口。通过 父类的引用指向子类的实例,来动态完成各个不同子类方法的调用。这里面就要涉及到重写和重载问题
  • 重写 和 重载 的区别

作用范围不同:重载发生在同一个类中,重写发生在父子类中

对于一个函数来说:

重载方法名必须相同,参数类型不同、个数不同、顺序不同;

返回值,可以不同;访问修饰符,可以不同

重写 方法名、参数列表必须相同 ;

返回值,范围要小于父类;访问修饰符,范围要大于父类,其中父类修饰符为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基础问题的更多相关文章

  1. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  2. [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)

    如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html   谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...

  3. 【JAVA面试题系列一】面试题总汇--JAVA基础部分

    JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...

  4. 最适合作为Java基础面试题之Singleton模式

    看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...

  5. java基础练习 字符串,控制流,日历,日期等

    1,对基本控制流程的一些练习 package org.base.practice3; import org.junit.Test; /** * Created with IntelliJ IDEA. ...

  6. Java基础知识【下】( 转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608360 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

  7. Java基础知识【上】(转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

  8. java基础学习03(java基础程序设计)

    java基础程序设计 一.完成的目标 1. 掌握java中的数据类型划分 2. 8种基本数据类型的使用及数据类型转换 3. 位运算.运算符.表达式 4. 判断.循环语句的使用 5. break和con ...

  9. Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

  10. java基础知识小总结【转】

    java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...

随机推荐

  1. python测试框架-pytest

    一.pytest 介绍.运行.参数化和数据驱动.Fixture pytest安装与介绍 官网 : pip install -U pytest 查看版本号:pytest --version 为何选择py ...

  2. 【刷题-LeetCode】306. Additive Number

    Additive Number Additive number is a string whose digits can form additive sequence. A valid additiv ...

  3. 【解决了一个问题】腾讯云中使用ckafka生产消息时出现“kafka server: Message contents does not match its CRC.”错误

    初始化的主要代码如下: config := sarama.NewConfig() config.Producer.RequiredAcks = sarama.WaitForAll // Wait fo ...

  4. 公司内部一次关于kafka消息队列消费积压故障复盘分享

    背景现象 1.20晚上8点业务线开始切换LBS相关流量,在之后的1个小时时间内,积压量呈上升趋势,一路到达50W左右,第二天的图没贴出具体是50W数字,以下是第一天晚上的贴图部分. 现象一: 现象二: ...

  5. gin中模型的绑定和验证

    要将请求体绑定到结构体中,使用模型绑定. Gin目前支持JSON.XML.YAML和标准表单值的绑定(foo=bar&boo=baz). Gin使用 go-playground/validat ...

  6. 开发者的瑞士军刀「GitHub 热点速览 v.22.04」

    Swiss Army knife 可以说是本周的关键词了,多个项目采用该词来描述它的特性:像是能全方位解决浏览器"网络"操作的 CyberChef 方便你进行数据加密.解编码,还有 ...

  7. 深入了解promise

    1. Promise基础 什么是回调地狱? 当使用回调函数来进行事件处理的时候,如果嵌套多层回调函数的时候,就会出现回调地狱,例如: method1(function(err, result) { i ...

  8. Vue3.2中的setup语法糖,保证你看的明明白白!

    vue3.2 到底更新了什么? 根据原文内容的更新的内容主要有以下 5 块: 1.SSR:服务端渲染优化.@vue/server-renderer包加了一个ES模块创建, 与Node.js解耦,使在非 ...

  9. 解决matplotlib中文不显示问题

    在导入库时添加如下几行代码 from pylab import mpl mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体 mpl.rcPa ...

  10. Vue3源码分析之 Ref 与 ReactiveEffect

    Vue3中的响应式实现原理 完整 js版本简易源码 在最底部 ref 与 reactive 是Vue3中的两个定义响应式对象的API,其中reactive是通过 Proxy 来实现的,它返回对象的响应 ...