侧边栏壁纸
博主头像
Zhangsnke博主等级

这是Zhangxike的平凡生活!

  • 累计撰写 16 篇文章
  • 累计创建 11 个标签
  • 累计收到 15 条评论

目 录CONTENT

文章目录

java基础知识(二)

Zhangsnke
2021-06-16 / 2 评论 / 0 点赞 / 927 阅读 / 4,155 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-07-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. String,StringBuffer和StringBuilder的区别

可变性
简单的来说,String类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是不可变的。而 StringBuilder 与 StringBuffer 都继承自 AbstractStringBuiler 类,而在AbstractStringBuilder 中也是使用字符数组保存字符串char[] value,但是没有 final 关键字修饰,所以这两种对象都是可变的。 StringBuilder 和 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder实现的。

AbstractStringBuilder.java

abstract class AbstractStringBuilder implements Appendable,CharSequence{
	char[] value;
	int count;
	AbstractStringBuilder(){}
	AbstractStringBuilder(int capacity){
	 value = new char[capacity];
	}
}

线程安全
String中对象是不可改变的,也就是理解为常量,线程安全。
AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity,append,insert,indexOf等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以线程是安全的。StringBuilder 并没有对方法进行同步加锁,所以是线程非安全的。

性能
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后指针指向新的 String 对象。StringBuffer 每次对 StringBuffer对象本身进行操作们不是生成新的对象并改变引用。相同情况下,使用 StringBuilder 相比 StringBuffer 仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。

使用建议

  1. 操作少量的数据 = String
  2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

以上三者的区别

2. 在一个静态方法内调用一个非静态成员变量为什么是非法的

静态方法是属于类的,而非静态方法是属于实例对象的。类的加载要早于实例对象,当一个对象被实例化出来时候,才有对象。所以当在静态方法中调用一个还没有出生的对象的属性的时候,无法调用。
反之 如果在非静态方法中调用静态方法,那么不算非法。

3. 在Java中定义一个不做事且没有参数的构造方法的作用

java程序在执行子类的构造方法之前,如果没有 super() 来调用父类特定的构造方法,则会调用父类中没有参数的构造方法。因此。如果父类中只是定义了有参的构造方法,而在子类中的构造方法没有用 super() 来调用父类中特定的构造方法,则在编译时会发生错误,因为 java程序在父类中找不到无参构造方法可供执行。解决办法就是在父类里添加无参构造方法。

4. 接口和抽象类的区别是什么

  • 接口的方法默认是 public,所有方法在接口中不能有实现(jdk8开始,接口方法可以有默认实现default function),抽象类可以有非抽象方法
  • 接口中的实例变量都是 final 类型的,而抽象类中不一定
  • 一个类可以实现多个接口,但是最多实现(继承)一个抽象类
  • 一个类实现接口的话要实现接口里所有的方法,而抽象类则不一定
  • 接口不能用 new 实例化,但可以声明,必须引用一个实现接口的对象,从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为规范。

5.成员变量和局部变量的区别

  • 语法上,成员变量属于类的(这里区分类与‘类’的区别),局部变量定义在方法中或者是方法的参数;成员变量可以被 public ,private,static 等修饰,而局部变量不能被访问修饰符以及 static 修饰;但是成员变量和局部变量都能被 final 修饰
  • 从变量在内存中的存储方法来看,成员变量是对象的一部分,而对象存在于堆内存中,局部变量存在栈内存
  • 从变量在内存中的生存时间来看,成员变量时对象的一部分,它随着对象的创建而存在;而局部变量随着方法的结束(出栈)而自动消失
  • 从赋值角度来看,成员变量如果没有赋值,则会自动按照类型的默认值赋值(int默认为0等)而局部变量必须要初始化,不会自动赋值

6. 构造函数的特性

  • 名称与类名相同
  • 没有返回值,但不能用 void 声明构造函数
  • 生成类的对象时自动执行,无需调用

7. == 与 equals()

==: 作用是比较两个对象的引用地址是否相等。即判断两个对象是不是同一个对象(这里需要区分基本类型和引用类型区别:基本类型 == 也是比较的值,引用类型 == 比较的是两个对象的内存地址)

equals(): 它的作用判断两个对象是否相等。但是一般有两种使用情况

  • 情况1: 类没有重写 equals() 方法,则通过 equals() 比较两个对象时,等价于通过 “==” 进行比较这两个对象
  • 情况2: 类重写了 equals() 方法。一般重写 equals() 方法来比较这两个对象的内容是否相等,若它们内容相等,则返回true(认为这两个对象相等)。一般重写了 equals() 方法,需要重写 hashCode()方法

例子:

public class test1{
	public static void main(String[] args){
		//a 为一个引用
		String a = new String("ab");
		//b 为另一个引用
		String a = new String("ab");
		//放在常量池中
		String aa = "ab";
		//从常量池中查找
		String bb = "ab";
		if(aa == bb){  //true
			System.out.println("aa == bb");
			if(a == b) //false
			System.out.println("a == b");
			if(a.equals(b)) //true
			System.out.println("a EQ b");
			if(36 == 36.0) //true
			System.out.println("36 == 36.0");
		}	
	
	}
}

说明 String 中的 equals() 是被重写过的(比较的是字符串内每一个字符是否相等),因为祖父类 Object 中的 equals 方法比较的是对象的内存地址,而 String 的 equals() 比较的是对象的值。
当创建 String 对象的时,虚拟机会在常量池中查找是否已有该字符串,如果存在和要创建的值相等的对象,则把它赋给当前引用,如果没有,则在常量池中继续创建一个 String 对象。

8.hashCode() 与 equals()

你有没有想过,为什么重写equals方法时必须要重写hashCode方法?

hashCode()
什么是 hashCode()? hashCode()的作用是获取哈希码,也成为了散列码。它实际上返回一个 int 整型,这个哈希码的作用是对该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 java 中的任何一个类都包含了 hashCode() 方法。散列表存储的是键值对(key-value),特点是能够依据“键”快速获取到对应的值,这就是利用率散列码(快速找到所需要的对象)。

为什么要有 hashCode()
拿 HashSet 如何查找重复元素举例。
当你把对象加入到 HashSet 时, HashSet 会先计算对象的 hashCode() 值来判断对象加入到的位置,同时也会和其他已经加入的对象的 hashCode() 进行值比较,如果没有符合相同的 hashCode(), HashSet 会假设对象没有重复,但是如果发现有相同的 hashCode() 值,这时候会调用 equals() 来检查 hashCode() 相等的对象是否真的相等。如果两者相同,那么 HashSet 就不会让其加入操作成功。 如果不相同,就会散列到其他位置。 hashCode() 存在大大减少了 equals() 的次数,相应的执行速度就会提高。

hashCode() 与 equals() 相关规定

  1. 如果两个对象相等,那么 hashCode() 则一定相等
  2. 如果两个对象相等,对这两个对象分别调用 equals() 方法,则都应该返回true
  3. 如果两个对象有相同的 hashCode()值,那么他们也不一定是相等的
  4. 因此,equals() 方法被重写过,那么 hashCode()方法也必须要被重写
  5. hashCode() 默认行为是对堆上的对象产生独特值,如果没有重写过 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
0

评论区