侧边栏壁纸
  • 累计撰写 43 篇文章
  • 累计创建 9 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

java 基础面试题

landonchan
2015-11-04 / 0 评论 / 0 点赞 / 158 阅读 / 11652 字
温馨提示:
欢迎留言讨论!若内容或图片失效,请留言反馈。若不小心影响到您的利益,请联系我们删除。

面向对象&面向过程

  • 面向过程:把问题分解成一个一个步骤,每个步骤用函数实现,形成调用链,依次调用。

  • 面向对象:把问题分解成步骤,然后对具体的步骤或者现实实体进行抽象,形成对象,通过对象之间的方法调用解决问题

面向对象的三大基本特征

  • 封装:把现实世界中的事物抽象成一个具体的类,把事物的具体属性和方法封装在类中,具体的调用方不必知道具体的细节,只需知道调用什么方法、有什么功能。

  • 继承:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。

  • 多态:允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

方法的重写和重载

  • 重写:类继承某个类或者实现某个接口,重写父类或者接口的方法,然后具体使用时父类或者接口的引用指向具体的子类或者实现类。方法名和参数参数列表、返回值完全一样。运行时绑定。满足条件:子类继承父类或者接口实现&子类重写父类方法或者实现接口方法&父类的引用指向子类。直接代码指定引用的叫静态多态(直接指定实现类),通过spi 或者类型判断等等手段,获取具体的实现类,叫动态多态。

  • 重载:同一个类中,方法名相同,参数列表不同,与返回值无关。编译期绑定,编译阶段就可以判断使用什么方法,降低运行时开销,代码更高效。

继承和实现区别

  • 接口可以继承接口,抽象类可以实现接口,抽象类可以继承具体类。普通类可以实现接口,也可以继承抽象类和普通类。

  • 继承只能单继承,一个类可以实现多个接口。

  • 不使用多继承,是会产生菱形问题。比如说基类A,类B,C继承 A,类 D 又继承 B,C,这时候要是去调用 D 中的方法,刚好 B,C 中都有,D 又没有重写,就不知道调用谁的了。

接口和抽象类区别

  • 接口只有抽象的方法,无具体实现。(java8后有具体的实现)

  • 接口的访问修饰符必须是 public(默认),抽象类可以是 private\default\public\protected。

  • 接口中的成员变量必须初始化。

  • 抽象类可以有构造器,但是接口不能有。

  • 接口可以被实现,接口之间可以继承,抽象类被继承。

  • 一个类可以实现多个接口,但是只能继承一个类。

  • 接口主要用于制定规范,抽象类主要是为了复用(模板模式)。

面向对象的五大基本原则

  • 单一职责:一个类最好只做一件事情。这样可以提高代码的可维护性,减少修改代码对各功能的影响。

  • 开放封闭:对修改封闭,对扩展开放。可以在不修改现有代码的情况下,扩展功能。比如说通过继承,不用修改原有的代码,重写方法,引用指向新实现类,这样新的功能使用使用新实现类,老的功能不受影响。

  • 里氏替换:子类可以扩展父类的功能,但不能改变父类原有的功能。子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

  • 依赖倒置:要面向接口编程,不要面向实现编程。

  • 接口隔离:使用多而小的接口,不要使用大而全。

基本类型&包装类

基本类型(8种)

byte:

  • byte 数据类型是8位、有符号的,以二进制补码表示的整数;

  • 最小值是 -128(-2^7)

  • 最大值是 127(2^7-1)

  • 默认值是 0

  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;

  • 例子:byte a = 100,byte b = -50。

short:

  • short 数据类型是 16 位、有符号的以二进制补码表示的整数

  • 最小值是 -32768(-2^15)

  • 最大值是 32767(2^15 - 1)

  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;

  • 默认值是 0

  • 例子:short s = 1000,short r = -20000。

int:

  • int 数据类型是32位、有符号的以二进制补码表示的整数;

  • 最小值是 -2,147,483,648(-2^31)

  • 最大值是 2,147,483,647(2^31 - 1)

  • 一般地整型变量默认为 int 类型;

  • 默认值是 0

  • 例子:int a = 100000, int b = -200000。

long:

  • long 数据类型是 64 位、有符号的以二进制补码表示的整数;

  • 最小值是 -9,223,372,036,854,775,808(-2^63)

  • 最大值是 9,223,372,036,854,775,807(2^63 -1)

  • 这种类型主要使用在需要比较大整数的系统上;

  • 默认值是 0L

  • 例子: long a = 100000Llong b = -200000L
    "L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。

float:

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;

  • float 在储存大型浮点数组的时候可节省内存空间;

  • 默认值是 0.0f

  • 浮点数不能用来表示精确的值,如货币;

  • 例子:float f1 = 234.5f。

double:

  • double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;

  • 浮点数的默认类型为 double 类型;

  • double类型同样不能表示精确的值,如货币;

  • 默认值是 0.0d

  • 例子:boolean one = true。

char:

  • char 类型是一个单一的 16 位 Unicode 字符;

  • 最小值是 \u0000(十进制等效值为 0);

  • 最大值是 \uffff(即为 65535);

  • char 数据类型可以储存任何字符;

  • 例子:char letter = 'A';。

有了基本数据类型还要有包装类

因为 java 是面向对象的语言。比如说说集合类的操作都是泛型,必须是 Object,int 这些是放不进去的。

基本类型和包装类的区别

  1. 默认值不同,包装类都是 null。

  2. 初始化方式不同,包装类要 new。

  3. 存储方式不同,基本类型是保存在栈上,包装类型保存在堆上。(JIT优化可能分配在栈上)

  4. rpc 接口应该使用在包装类,避免 Null和0的区别。

拆装箱

拆箱就是指把包装类转化为基本类型,比如 new Integer(10).intValue()。

装箱就是指把基本数据类型转化为包装类,比如 Integer.valueOf(10)。其中-128到127是有缓存的,可以通过-XX:AutoBoxCacheMax=Size 来进行修改。

金额

不能使用 float 和 double

因为10进制转2进制。整数是除以2取余,逆序排列,小数是乘以2取整,顺序排列。

不是所有的10进制都能转换成2进制的整数,比如0.1就二进制就是无限循环下去,这样精度就会丢失。

应该使用 BigDecimal。

BigDecimal 使用方式

用 BigDecimal.valueOf("0.1")。

不要用 equals 比较,equals 是会比较对象的属性的,比如精度。

比较用 compareTo()。

String&StringBuilder&StringBuffer

String

不可变,内部方法都会生成新的 String 对象,字符串太常用了,保证线程安全。

"+"号拼接,反编译过来其实就是 StringBuilder 拼接。

String a=new String("abc"); 创建1个或2个对象。

"abc"这是字面量,如果不在字符串常量池中,会先在字符串常量池中创建。如果在字符串常量池中,则返回常量池中的引用。

字面量有可能一开始就在 class 常量池中,并不会立刻解析成对象,然后第一次调用的时候才会在字符串常量池中创建。

String.intern()方法:

如果字符串常量池中有这个字符串,则返回对象的引用。

如果没有,则会在字符床常量池中先创建,然后返回引用。

使用的好的话,可以避免大量字符串的创建。

使用时要注意 JDK 版本这些都是字符串维护,会被提前加入到字符串常量池中。

String 的长度有限制,如果是编译期,长度是65535,运行期是 Integer.MAX_VALUE。

编译期是用2位 byte 来存储长度,故2的8次方-1。

运行期长度是 int,故 Integer.MAX_VALUE。

StringBuilder

线程不安全,可以拼接字符串。由于 JIT 优化,一般情况下,会栈上分配。

StringBuffer

线程安全,效率低,底层是通过synchronized来实现的。

泛型

泛型的实现是通过类型擦除来实现的,也就是你写好的 java 类,编译成.class 文件的时候就已经被编译成具体的类型了。JVM 是不知道什么是泛型的,都是具体的类型。

java 很多实现都是这样,减少运行时的损耗。

0

评论区