new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放
在栈内存中)。一个对象引用可以指向0个或1个对象 比如:一根绳子可以不系气球,也可以系一个气
球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)
1、 作用域 - 成员变量:针对整个类 - 局部变量:只在某个范围内有效。(一般指的就是方法,语句体 2、存储位置: - 成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存 - 局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释 3、生命周期 - 成员变量:随着对象的创建而存在,随着对象的消失而消失 - 局部变量:当方法调用完,或者语句结束后,就自动释 4、初始值 - 成员变量:有初始默认值 - 局部变量:没有默认初始值,使用前必须赋值
在java中,可以将一个类的定义放在另一个类的内部就行定义,这就是内部类。内部类本身就是类的一个类的属性,与其他属性定义方式一直
内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。
成员内部类
public class Outer { private static int radius = 1; static class StaticInner { public void visit() { System.out.println("visit outer static variable:" + radius); } } }
new 外部类.静态内部类()
,如下:Outer.StaticInner inner = new Outer.StaticInner(); inner.visit();
成员内部类:
public class Outer { private static int radius = 1; private int count = 2; class Inner { public void visit() { System.out.println("visit outer static variable:" + radius); System.out.println("visit outer variable:" + count); } } }
外部类实例.new 内部类()
,如下:Outer outer = new Outer() Outer.Inner inner = outer.new Inner(); inner.visit()
局部内部类
public class Outer { private int out_a = 1; private static int STATIC_b = 2; public void testFunctionClass() { int inner_c = 3; class Inner { private void fun() { System.out.println(out_a); System.out.println(STATIC_b); System.out.println(inner_c); } } Inner inner = new Inner(); inner.fun(); } public static void testStaticFunctionClass() { int d = 3; class Inner { private void fun() { // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量 System.out.println(STATIC_b); System.out.println(d); } } Inner inner = new Inner(); inner.fun(); } }
public static void testStaticFunctionClass(){ class Inner { } Inner inner = new Inner() }
匿名内部类
public class Outer { private void test(final int i) { new Service() { public void method() { for (int j = 0; j < i; j++) { System.out.println("匿名内部类"); } } }.method(); } } //匿名内部类必须继承或实现一个已有的接口 interface Service{ void method(); }
new 类/接口{ //匿名内部类实现部分 }
1、一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
2、内部类不为同一包的其他类所见,具有很好的封装性;
3、内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
4、匿名内部类可以很方便的定义回调
public class Outer { void outMethod() { final int a = 10; class Inner { void innerMethod() { System.out.println(a); } } } }
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数
据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;
若它们的内容相等,则返回 true (即,认为这两个对象相等)。
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的
当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
HashCode如何检查重复
两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
hashCode和equals方法的关系
面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”
hashCode()介绍
hashCode()的作用就是获取哈希码,也成为散列码,它实际返回一个int的整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
为什么要有 hashCode
我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:
hashCode()与equals()的相关规定
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据