Java中的一些基础知识

  1. 类中没有写或者修改成员变量的方法,例如:setxxx。只提供构造函数,一次生成,永不改变。

  2. 确保类中的所有方法不会被子类覆盖,可以通过把类定义为final或者把类中的方法定义为final来达到这个目的。

  3. 如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量是需要通过clone方法,来确保类的不可变性。

  4. 如果有必要,可以通过覆盖Object类的equals()方法和hashCode()方法。

由于类的不可变性,在创建对象的时候就需要初始化所有的成员变量,因此最好提供一个带参数的构造函数来初始化这些成员变量。

一个错误示范:

public class ImmutableClass {

private Date d;

public ImmutableClass(Date d){

this.d = d;

}

public void printState(){

System.out.println(d);

}

}

public class Test {

public static void main(String[] args) {

Date d = new Date();

ImmutableClass immu = new ImmutableClass(d);

immu.printState();

d.setMonth(5);

immu.printState();

}

}

复制代码

image.png

由于Date的对象的状态是可以被改变的,而ImmutableClass保存了Date类型对象的引用,当被引用的对象的状态改变的时候会导致ImmutableClass对象状态的改变。

正确的实现方式为:

public class ImmutableClass {

private Date d;

public ImmutableClass(Date d){

// this.d = d;

this.d = (Date)d.clone();// 解除了引用关系

}

public void printState(){

System.out.println(d);

}

}

public class Test {

public static void main(String[] args) {

Date d = new Date();

ImmutableClass immu = new ImmutableClass(d);

immu.printState();

d.setMonth(5);

immu.printState();

}

}

复制代码

image.png

不可变类的优缺点:

  • 优:不可变类具有使用简单、线程安全、节省内存等优点

  • 缺:不可变的对象会因为值的不同而产生新的对象,导致无法预料的问题

Question:

对于一些敏感的数据(例如密码),为什么使用字符串数组存储比使用String安全?

在Java中,String是不可变类,被存储在常量字符串池中,从而实现了字符串的共享,减少了内存开支。正因为如此,一旦一个String类型的字符串被创建出来,这个字符串就会存在于常量池中,知道被垃圾回收器回收为止。

因此,即使这个字符串(比如密码)不再被使用,仍然会在内存中存在一段时间(只有垃圾回收器才会回收这块内容,程序员无法直接回收字符串)。此时有权限访问memory dump(存储器转储)的程序都可能会访问到这个字符串,从而把敏感的数据暴露出去,这是一个非常大的安全隐患。

如果使用字符数组,一旦程序不再使用这个数据,程序员可以把字符数组的内容设置为空,此时这个数据在内存中就不存在。

也就是说,跟String相比,使用字符数组,程序员对数据的生命周期有更好的控制,增强安全性。

1.2 “= =”、equals和hashcode


1.2.1 “= =”

“==”运算符用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,

  • 要比较两个基本类型的数据或两个引用变量是否相等,只能使用“==”运算符.

  • 要比较两个引用变量是否指向同一块内存,可以使用“= =”

  • 要比较两个引用变量的对象内容是否相等,无法使用"= ="

1.2.2 equals

Object类中定义的equals(Object)方法是直接使用“”运算符比较的两个对象,所以在没有覆盖equals(Object)方法的情况下,equals(Object)与“”运算符一样,比较的是引用。

相比“==”运算符,因为equals(Object)方法的特殊之处就在于它可以被覆盖,所以可以通过覆盖的方法让它不是比较引用而是比较数据内容

1.2.3 hashCode

Object类中的hashCode()方法返回对象在内存中地址转换成的一个int值,所以如果没有重写hashCode()方法,那么任何对象的hashCode()方法都是不相等的。

equals方法和hashCode方法的区别?

  • 一般来讲,equals方法是给用户调用的,如果需要判断两个对象是否相等,可以重写equals方法,然后在代码中调用,即可判断是否相等

  • 对于hashCode()方法,用户一般不会去调用它。多用在hashmap、hashset等需要判断元素是否重复的地方。

一般在覆盖equals方法的同时也要覆盖hashCode()方法,否则会违反Object.hashCode的通用约定,导致该类无法与所有基于hash值的集合类结合正常运行。

1.3 值传递和引用传递


按值传递指的是在方法调用时,传递的参数是实参值的拷贝按引用传递指的是在方法调用时,传递的参数是实参的引用,也可以理解为实参所对应的内存空间的地址

public class Test {

public static void testPassParameter(StringBuffer s1,int n){

s1.append(" World");

n = 8;

}

public static void main(String[] args) {

StringBuffer sb = new StringBuffer(“Hello”);

int n = 1;

testPassParameter(sb,n);

System.out.println(sb);

System.out.println(n);

}

}

复制代码

image.png

从运行结果看,int作为参数的时候,对形参的修改不会影响实参,对于StringBuffer类型的参数,对形参的修改影响到了实参。可以理解为:基本类型的参数时按值传递,引用类型的参数时引用传递。

实际上,Java语言中的引用传递还是值传递(传递的是地址的值)。

1.4 Java关键字


1.4.1 static

static关键字主要有两个作用:

1、为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。

2、实现某个方法或属性与类而不是对象关联在一起

也就是说,在不创建对象的情况下就可以通过类来直接使用类的方法或者属性

static可修饰的元素

  • 变量:静态变量,可以跨越代码块访问

  • 方法:静态方法,可以跨越代码块访问

  • 代码块:静态代码块,只能定义在类定义下,在类被加载时执行

  • 内部类:静态内部类,该类定义可以有外部类名引用

  • 导入包:静态导入包,导入指定的static变量

加载时机

static,静态,表示随着类的加载而加载,不会重复加载,执行顺序在main方法执行。在JVM内存中,static修饰的变量存在于方法区中。

1.4.2 final

final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、类不可继承(不能再派生处新的子类)。

  • final属性:被final修饰的变量不可变,不可变又两重含义,一是引用不可变,二是对象不可变。final指的是哪种含义?

public class Test {

public static void main(String[] args) {

final StringBuffer sb = new StringBuffer(“Hello”);

sb = new StringBuffer(“Hello World!”);

}

}

复制代码

编译期间错误

public class Test {

public static void main(String[] args) {

final StringBuffer sb = new StringBuffer(“Hello”);

sb.append(" World!");

System.out.println(sb);

}

}

复制代码

运行结果为:Hello World!

可以看出,final指的是引用不可变,只能之现象初始时指向的那个对象,而不关心对象内容的变化。

final变量初始化的几个方式:

  1. 在定义的时候初始化

  2. final成员变量可以在初始化块中初始化,但不可在静态初始化块中初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值