java中==和equals和hashCode的区别 ?


   java中==和equals和hashCode的区别 ?

1、基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 
他们之间的比较,应用双等号(==),比较的是他们的值。

2、引用数据类型(类) 
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。

3、hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。 
两个obj,如果equals()相等,hashCode()一定相等。 
两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。 
所以: 
  可以考虑在集合中,判断两个对象是否相等的规则是: 
    第一步,如果hashCode()相等,则查看第二步,否则不相等; 
    第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。 
1. new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。>2. 比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal.

int、char、long各占多少字节数 ?

1字节: byte , boolean 
2字节: short , char 
4字节: int , float 
8字节: long , double 
注:1字节(byte)=8位(bits)

int与integer的区别

1、Integer是int的包装类,int则是java的一种基本数据类型 
2、Integer变量必须实例化后才能使用,而int变量不需要 
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值 
4、Integer的默认值是null,int的默认值是0

延伸: 
关于Integer和int的比较 
1、由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。

Integer i = new Integer(100); 
Integer j = new Integer(100); 
System.out.print(i == j); //false

2、Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)

Integer i = new Integer(100); 
int j = 100; 
System.out.print(i == j); //true

3、非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)

Integer i = new Integer(100); 
Integer j = 100; 
System.out.print(i == j); //false

4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false

Integer i = 100; 
Integer j = 100; 
System.out.print(i == j); //true

Integer i = 128; 
Integer j = 128; 
System.out.print(i == j); //false

对于第4条的原因: 
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:

public static Integer valueOf(int i){ 
assert IntegerCache.high >= 127; 
if (i >= IntegerCache.low && i <= IntegerCache.high){ 
return IntegerCache.cache[i + (-IntegerCache.low)]; 

return new Integer(i); 
}

java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了

谈谈对java多态的理解

父类的引用指向子类的对象 
同一消息可以根据发送对象的不同而采用多种不同的行为方式

void doSomething(Shape shape){
        shape.draw();
         .
         .
         shape.erase();
}

Circle circle = new Cricle();

Traingle traingle = new Traingle();

Line line = new Line();

doSonething(circle);

doSonething(traingle);

doSonething(line);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

String、StringBuffer、StringBuilder区别

String 字符串常量 
StringBuffer 字符串变量(线程安全) 
StringBuilder 字符串变量(非线程安全) 
1.三者在执行速度方面的比较:StringBuilder > StringBuffer > String 
2.String <(StringBuffer,StringBuilder)的原因 
    String:字符串常量 
    StringBuffer:字符创变量 
    StringBuilder:字符创变量 
从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问 ,比如这段代码:

1 String s = "abcd";
2 s = s+1;
3 System.out.print(s);// result : abcd1
  • 1
  • 2
  • 3

我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多低。 
  而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。

3.一个特殊的例子:

String str = “This is only a” + “ simple” + “ test”;
StringBuffer builder = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
  • 1
  • 2

你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:

    String str = “This is only a” + “ simple” + “test”;

  其实就是:

    String str = “This is only a simple test”;

  所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:

    String str2 = “This is only a”;

    String str3 = “ simple”;

    String str4 = “ test”;

    String str1 = str2 +str3 + str4;

    这时候JVM会规规矩矩的按照原来的方式去做。

什么是内部类?内部类的作用

内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类。 
内部类的主要作用如下:

  1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类

  2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据

  3. 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便

内部类有几种呢?

 成员内部类

 静态内部类

 方法内部类

 匿名内部类
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

抽象类和接口区别

接口类描述的是行为 抽象类描述的是根源; 
接口是对动作的抽象,抽象类是对根源的抽象。 
抽象类

抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。
  • 1
  • 2

接口

接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。
  • 1
  • 2

1.抽象类可以不包含静态方法,接口也不能包含静态方法; 
2.抽象类和接口都可以包含静态成员变量,抽象类中静态成员变量访问类型可以任意,但接口中定义的变量只能是public static final 类型,并且默认为public static final 类型; 
3.抽象类中可以包含普通成员变量,接口中没有普通成员变量。 
4.抽象类中的方法method不能同时是静态的;

抽象类的意义

1,为子类提供一个公共的类型;

2,封装子类中重复内容(成员变量和方法);

3,定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。

抽象类与接口的应用场景

  1. 定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。
  2. 某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。
  3. 规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能

抽象类是否可以没有方法和属性?

可以

接口的意义

接口的最主要的作用是达到统一访问,就是在创建对象的时候用接口创建,【接口名】 【对象名】=new 【实现接口的类】,这样你像用哪个类的对象就可以new哪个对象了,不需要改原来的代码,就和你的USB接口一样,插什么读什么,就是这个原理

解耦,可扩展这是设计接口的主要原因之一

泛型中extends和super的区别

<? extends T>限定参数类型的上界:参数类型必须是T或T的子类型 
<? super T> 限定参数类型的下界:参数类型必须是T或T的超类型 
总结为: 
<? extends T> 只能用于方法返回,告诉编译器此返参的类型的最小继承边界为T,T和T的父类都能接收,但是入参类型无法确定,只能接受null的传入 
<? super T>只能用于限定方法入参,告诉编译器入参只能是T或其子类型,而返参只能用Object类接收? 既不能用于入参也不能用于返参

父类的静态方法能否被子类重写

java中静态属性和和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏。

进程和线程的区别

进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程:进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

1 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

2 线程的划分尺度小于进程,使得多线程程序的并发性高。

3 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 
4 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程 不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 
5 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

final,finally,finalize的区别

Final用于修饰类、成员变量和成员方法。final修饰的类,不能被继承(String、StringBuilder、StringBuffer、Math,不可变类),其中所有的方法都不能被重写,所以不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,和final起相反的作用);Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法;Final修饰的成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。 
Finally通常和try catch搭配使用,保证不管有没有发生异常,资源都能够被释放(释放连接、关闭IO流)。

Finalize是object类中的一个方法,子类可以重写finalize()方法实现对资源的回收。垃圾回收只负责回收内存,并不负责资源的回收,资源回收要由程序员完成,Java虚拟机在垃圾回收之前会先调用垃圾对象的finalize方法用于使对象释放资源(如关闭连接、关闭文件),之后才进行垃圾回收,这个方法一般不会显示的调用,在垃圾回收时垃圾回收器会主动调用。

序列化的方式

什么是序列化?

把Java对象转换为字节序列,并存储至一个储存媒介的过程。

什么是反序列化?

把字节序列恢复为Java对象的过程。 
Android开发中的序列化有两种方法。 
第一种是实现Serializable接口(是JavaSE本身就支持的),第二种是实现Parcelable接口(是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。

Serializable 和Parcelable 的区别

1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。

3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable。

4)Serializable的实现,只需要implements Serializable 即可。这只是给对象打了一个标记,系统会自动将其序列化。

5)Parcelabel的实现,不仅需要implements Parcelabel,还需要在类中添加一个静态成员变量CREATOR,这个变量需要实现 Parcelable.Creator 接口。

6) Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化

静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?

java中静态属性和和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏。 
静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成的,不需继承机制就可以调用如果子类里面定义了静态方法和属性,那么这时候父类的静态方法 或属性称之为“隐藏”,你如果想要调用父类的静态方法和属性,直接通过父类名.方法名或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是 跟实例方法和属性不太一样,存在“隐藏”的这种情况。

例证如下:
package com.etc;
public  class A//父类
{
    public static String str = "静态属性";
    public String name = "非静态属性";
    public static void sing()
    {
        System.out.println("静态方法");
    }

    public void run()
    {
        System.out.println("非静态方法");
    }
}
package com.etc;
public class B extends A //子类B
{
    public static String str = "B该改写后的静态属性";
    public String name ="B改写后的非静态属性";
    public static void sing()
    {
        System.out.println("B改写后的静态方法");
    }
}
package com.etc;
public class C extends A //子类C继承A中的所有属性和方法
{
}
package com.etc;
public class Test//测试类
{
    public static void main(String[] args)
    {
        C c = new C();
        System.out.println(c.name);
        System.out.println(c.str);
        c.sing();//输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承

        A c1 = new C();
        System.out.println(c1.name);
        System.out.println(c1.str);
        c1.sing();//结果同上,输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承

        B b = new B();
        System.out.println(b.name);
        System.out.println(b.str);
        b.sing();//结果都是子类的非静态属性,静态属性和静态方法,这里和非静态属性和非静态类的继承相同


        A b1 = new B();
        System.out.println(b1.str);//结果是父类的静态属性,说明静态属性不可以被重写,不能实现多态
        System.out.println(b1.name);//结果是父类的非静态属性,说明非静态属性不可以被重写,不能实现多态
        b1.sing();//结果都是父类的静态方法,说明静态方法不可以被重写,不能实现多态
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

静态内部类的设计意图

说静态内部类之前,先了解下成员内部类(非静态的内部类)。

成员内部类

成员内部类也是最普通的内部类,它是外围类的一个成员,所以它可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

在成员内部类中要注意两点:

成员内部类中不能存在任何static的变量和方法;

成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

静态内部类

静态内部类与非静态内部类之间存在一个最大的区别:非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。

没有这个引用就意味着:

它的创建是不需要依赖于外围类的。

它不能使用任何外围类的非static成员变量和方法。

成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用

广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类

成员内部类 
可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员),不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问: 
外部类.this.成员变量 
外部类.this.成员方法 
虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问 
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。 
局部内部类 
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内,注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。 
匿名内部类 
匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。 
匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。 
.静态内部类 
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

谈谈对kotlin的理解

1,空类型安全 
2,Lambda 表达式 
3,扩展方法 
4,类型推导 
5,胜任Java能做的所有事,并且比Java更简单 
6,没有分号 ..

闭包和局部内部类的区别

闭包就是把函数以及变量包起来,使得变量的生存周期延长。闭包跟面向对象是一棵树上的两条枝,实现的功能是等价的。

string 转换成 integer的方式及原理

public static Integer valueOf(String s) throws NumberFormatException{
        return new Integer(parseInt(s, 10));
} 

猜你喜欢

转载自blog.csdn.net/l15336134466/article/details/79577592