Java基础

Java和c++区别

  • c++是编译型语言,首先将源代码翻译成机器语言,再由机器运行机器码,执行速度快,效率高,跨平台性差。多继承
  • Java是解释型语言,源代码不是直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。执行速度慢,效率低,跨平台性好。单继承

如何理解面向对象和面向过程?

  • 面向过程就是把解决问题的过程拆成一个个方法,通过方法的执行来解决问题。
  • 面向对象需要把属性行为封装成对象,基于对象进行业务逻辑的实现。面向对象又封装、继承、多态三大基本特征。面向对象开发的程序一般更易维护、易复用、易扩展。

封装:就是把一个事物抽象成Java类,然后类中存放属性和方法。把属性隐藏在对象内部,不允许外界直接访问对象的内部信息。提供get,set方法来操作属性。

继承:就是复用,子类继承父类就可以把父类的属性、方法继承过来。

  • 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的父类中的私有属性和私有方法子类是无法访问的,只是拥有。
  • 子类可以可以拥有自己的属性和方法,可以对父类进行扩展。

多态:父类中的属性和方法可以通过重写使父类和子类具有不同的实现,同一个属性和方法在父类和子类中有不同的含义。

基本数据类型

在这里插入图片描述

基本类型和包装类型

包装类型就是为了让基本类型具有对象的特征,相当于把对象包装起来,使它具有对象的性质,为它增加了属性和方法。

区别:

  1. 默认值不同,基本类型的默认值就是0,false啊,包装类默认值是null;
  2. 初始化方式不同,包装类需要new
  3. 包装类存在堆中的,基本类型存在栈中

自动装箱拆箱:
装箱:基本类型->包装类型(valueOf())
拆箱:包装类型->基本类型(xxxValue())

场景:

  1. 将基本类型放入集合类
  2. 包装类型比较大小
  3. 包装类型的运算
  4. 三目运算符

包装类型的缓存机制:
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。会复用已有对象,这个区间内可以用==去判断,还是推荐所有整型包装类对象之间值的比较,全部使用 equals 方法比较。

如何解决浮点数运算的精度丢失问题?
BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。
如何比较BigDecimal?
不能使用equals来比较,因为equals不止比较值还比较标度,如果值相等标度不同也会返回false,应该用compareTo方法,这个方法只比较值。

成员变量和局部变量

  • 成员变量属于类,局部变量属于代码块或者方法,成员变量可以被public,private,static等修饰符所修饰,局部变量不能,但是他俩都可以被final修饰。
  • 如果成员变量被static修饰,这个成员变量是属于类的,如果没有被static修饰则是属于实例的,对象存在堆内存中,局部变量存在栈中。
  • 成员变量是对象的一部分,它随着对象的创建而存在,局部变量随着方法的结束而消亡。

静态变量

静态变量就是被static关键字修饰的变量,它可以被类的所有实例共享,无论一个类创建了多少实例都共享同一个静态变量,静态变量只会分配一次内存。

静态方法为什么不能调用非静态成员

  • 静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问,非静态成员属于实例对象,只有对象实例化之后才存在。
  • 静态方法调用非静态成员,可能这个非静态成员还不存在,属于非法操作。

重载和重写有什么区别?

重载:在一个类中方法名相同,参数不同,访问修饰符也可以不同。
重写:子类对父类的方法进行重写,子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明。

方法的重写要遵循“两同两小一大”:

  • “两同”即方法名相同、形参列表相同;
  • “两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;
  • “一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。

什么是可变长参数?

就是不确定参数的个数,支持传入0个或者多个参数。

public static void method1(String... args) {
   //......
}
public static void method2(String arg1, String... args) {
   //......
}

遇到方法重载的情况怎么办呢?会优先匹配固定参数还是可变参数的方法呢?

答案是会优先匹配固定参数的方法,因为固定参数的方法匹配度更高。

对象的相等和引用相等的区别

  • 对象的相等一般比较的是内存中存放的内容是否相等。
  • 引用相等一般比较的是他们指向的内存地址是否相等。

接口和抽象类有什么区别

  • 接口主要用于制定规范,抽象类主要目的是为了复用,可以把公共的部分提取到抽象类中的普通方法中,通过类去继承抽象类在类中进行重写实现不同的部分。
    在这里插入图片描述
  • 接口中的成员变量只能是常量(public static final 类型)
  • 一个类只能继承一个类,但是可以实现多个接口。
  • 都可以包含抽象方法(实现的这个类必须重写这个类所有的抽象方法)。接口中可以有默认实现的方法(Java 8 可以用 default 关键字在接口中定义默认方法,可以不必须重写)。接口中是没有实现的代码的。

引用类型和基本类型

  • 基本数据类型:变量名指向具体的数值,引用类型:变量名指向的不是具体的数值而是内存地址;
  • 基本数据类型被创建时在栈内存中会被划分出一定的内存并将数值存在栈内存中,引用数据类型被创建时会在栈内存中分配一块空间,在堆内存中也会分配一块空间来存储数据,然后栈中的引用指向堆中的对象地址。
    在这里插入图片描述

深拷贝和浅拷贝的区别

  • 浅拷贝:如果对象是引用类型的话,浅拷贝就是只会复制他的引用,和原对象共用一个对象。
    Cloneable中的clone()就是浅拷贝,BeanUtils.copyProperties也是浅拷贝。引用类型修改后是会有影响的(数组、实体类(先get得到对象之后对对象中的属性做修改))。
    在这里插入图片描述

  • 深拷贝:完全复制整个对象

  1. 需要重写clone()方法
@Override
public Person clone() {
    try {
        Person person = (Person) super.clone();
        //将对象中的属性也复制
        person.setAddress(person.getAddress().clone());
        return person;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}
  1. 序列化实现深拷贝
    可以把对象序列化为JSON字符串,再从字符串中反序列化成对象
//如使用fastjson
User newUser= JSON.parseObject(JSON.toJSONString(user),User.class);
  • 引用拷贝:两个不同的引用指向同一个对象
    在这里插入图片描述

为什么要有hashCode?

  • 因为在一些容器像是HashMap、HashSet中,有了hashCode()判断容器中是否有这个元素的效率更高。
  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。

String、StringBuffer、StringBuilder 的区别?

  • String是不可变的(使用final修饰),String的一些方法substring、concat等,在代码中如果涉及到字符串的修改会new String()的方式新建一个字符串。

  • StringBuffer和StringBuilder都继承自 AbstractStringBuilder 类,是可变的。而StringBuffer是线程安全的,StringBuilder是非线程安全的。

  • 对于三者使用的总结:
    操作少量的数据: 适用 String
    单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
    多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

字符串常量池

  • 作用:避免字符串的重复创建
  • 创建一个字符串对象的时候会先去常量池里看这个这个对象的引用,如果没有会先在常量池中保存(String.intern 没有就保存有就返回引用),然后在堆空间中创建,如果有则只会在堆空间中创建。
    所以String s1 = new String(“abc”);会创建 1 或 2 个字符串对象。取决于常量池中有没有该字符串对象的引用。
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
  • 已经确定值的字符串在编译阶段就已经被放入字符串常量池。
  • 常量折叠会把常量表达式的值求出来作为常量嵌在最终生成的代码中对于 String str3 = “str” + “ing”; 编译器会给你优化成 String str3 = “string”; 。
final String str1 = "str";
final String str2 = getStr();
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 在堆上创建的新的对象
System.out.println(c == d);// false
public static String getStr() {
      return "ing";
}

finally 中的代码一定会执行吗?

正常情况下会的,还有一些意外情况像是JVM终止运行、关闭cpu、程序所在的线程已死亡。

什么是泛型?

通过泛型来指定传入的对象类型,增强代码的可读性。
哪里用到了泛型:自定义接口通用返回结果CommonResult通过参数T可根据具体的返回类型动态指定结果的数据类型。

反射

过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

为什么Java中的负数取绝对值不一定是正数?

int的取值范围是-2^31 - 2^31-1,当对最小值取绝对值的时候,会发生越界计算结果刚好是-2的31次方的补码,所以得到的数字还是个负数。
在这里插入图片描述
解决方式是将int转为long类型,这样就不会出现越界了

long abs =  Math.abs((long)-2147483648);

说几个常见的语法糖

  1. switch支持String
String str = "world";
switch(str){
case "hello":
   System.out.println("hello");
   break;
case "world":
   System.out.println("world");
   break;
default:
   break;
}

是通过hashCode()和equals()实现的
2. 泛型
3. 自动拆箱和装箱
4. 方法变长参数
5. lambda表达式

Java中是值传递还是引用传递?

只有值传递

  1. 基本数据类型:传递的是参数副本,对副本操作不会影响到参数本身。
public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;
    swap(num1, num2);
    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

在这里插入图片描述

  1. 引用数据类型:传递的是参数的地址,在方法中对传递过来的参数做修改,原来的参数也会受影响。交换两个参数,原来的参数不会受影响,因为只是交换了副本对象的引用。而原来参数的引用没有受影响。引用传递是形参和实参共用一个引用,值传递会新创建一个地址的副本,两个参数不共用引用,他们各自有各自的引用。
	public static void main(String[] args) {
      int[] arr = { 1, 2, 3, 4, 5 };
      System.out.println(arr[0]);
      change(arr);
      System.out.println(arr[0]);
	}

	public static void change(int[] array) {
      // 将数组的第一个元素变为0
      array[0] = 0;
	}

在这里插入图片描述

public class Person {
    private String name;
   // 省略构造函数、Getter&Setter方法
}

public static void main(String[] args) {
    Person xiaoZhang = new Person("小张");
    Person xiaoLi = new Person("小李");
    swap(xiaoZhang, xiaoLi);
    System.out.println("xiaoZhang:" + xiaoZhang.getName());
    System.out.println("xiaoLi:" + xiaoLi.getName());
}

public static void swap(Person person1, Person person2) {
    Person temp = person1;
    person1 = person2;
    person2 = temp;
    System.out.println("person1:" + person1.getName());
    System.out.println("person2:" + person2.getName());
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值