java进阶的16个知识点

时间:2022-04-27
本文章向大家介绍java进阶的16个知识点,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1.float 类型在java中占4个字符,long类型在java中占8个字符,为什么float类型比long类型取值范围大? float   32位二进制码中,第32位  1位符号位   第23-31位 8位指数位  第0-22位  23位尾数位 指数位 (-128—127)+2^7 表示为10进制    (1位符号位所示符号)(23位尾数位对应十进制数)*10^(8位指数位对应十进制数)

long 64位

表示为10进制  (64位二进制数对应的十进制数)

2.i++和++i到底有什么不同。仅仅是先加和后加的区别么? i++: 先将i值赋给一个临时变量,在进行i+=1后将临时变量返回

++i: i+=1

3.java中无优先级的运算顺序是怎样的?i+++j是计算(i++)+j还是i+(++j)?

从左到右,计算(i++)+j

public class TestOperatSequence {
	//运算从左到右结合
	public static void main(String[] args) {
		int i=1,j=2;
		System.out.println(i+++j);
		i=1;j=2;
		System.out.println((i++)+j);
		i=1;j=2;
		System.out.println(i+(++j));
	}
}

运行结果:

3
3
4

再看这段代码:

public class TestOperatSequence {
	//运算从左到右结合
	public static void main(String[] args) {
		int[] a={1,2,3};
		int i=1;
		a[++i]+=i++;  //3+2
		for(int item:a)
			System.out.println(item);
	}
}

运行结果:

1
2
5

虽然赋值是右赋左,但运算顺序显然是先++i后i++,从左向右

4.为什么要为String对象建立常量池?String常量池有什么好处? 节约内存,在利用字面量创建字符串对象时的时候,如果该对象在常量池中已存在,则直接使用该对象,而不必重新分配内存创建新对象,可以实现多线程共享资源 String编译时常量会在编译的时候被加入到String常量池中,使用intern关键字,如果常量池中已存在该对象,直接返回该对象,如果不存在,则将对象放入常量池中后再返回该对象

5.使用“+”可以连接两个字符串,如何进行连接的? Oracle:

new StringBuilder().append(obj1).append(obj2).toString();

Eclipse: 当左边参数为基本数据类型时,会先将基本数据类型转化为String类型;其余同Oracle

new StringBuilder(String.valueOf(i1)).append(obj2).toString();

在字符串进行频繁拼接的时候,使用StringBuilder可以节省实例化StringBuilder所耗时间

public class TestStringPlus {
	public static void main(String[] args) {
		System.out.println("Direct plus time:"+getDirectTime());
		System.out.println("StringBuilder plus time:"+getStringBuilderTime());
	}
	
	public static long getDirectTime(){
		long now=System.nanoTime();
		@SuppressWarnings("unused")
		String str="";
		for(int i=0;i<10000;i++)
			str+="a";
		return System.nanoTime()-now;
	}
	
	public static long getStringBuilderTime(){
		long now=System.nanoTime();
		String str="";
		StringBuilder sb=new StringBuilder(str);
		for(int i=0;i<10000;i++)
			sb.append("a");
		return System.nanoTime()-now;
	}
}

运行结果:

Direct plus time:57455979
StringBuilder plus time:443259

6.数组长度时,可以使用byte,short,int,能否使用long和char? 不能使用long,范围太大,不必要 可以使用char,用该字符对应的ASCLL码作为数组长度

7.移位运算:5<<35,会首先进行35%32的求余运算吗? 在java中int占4个字节32位,long占8个字节64个字节,当移位超过31或者63位时,移位便没有什么意义了。所以在左侧操作数为int类型的时候,取右侧操作数补码后5位(<=31)作为移位位数,左侧操作数为long类型的时候,取右侧操作数补码后6位(<=63)作为移位位数

public class TestBitMove {
	public static void main(String[] args) {
		//5    00000101		00101000
		System.out.println(5<<35);
		System.out.println(5<<3);
		//30  00011110		00000000
		System.out.println(30>>70);
		System.out.println(30>>6);
		
		//-10 10001010		01110110	移位数为22位
		System.out.println(5<<-10 );
		System.out.println(5<<22);
	}
}

运行结果:

40
40
0
0
20971520
20971520

8.从JDK1.7开始,switch语句可以支持String类型,那么在底层是如何实现的呢? 根据String的hashcode创建一个变量,利用该变量进行switch分支判定

9.如果重写了equals方法,为什么还要重写hashcode方法? 不重写equals的话,equals继承自Object,判断方法依旧是== 键值对集合是利用hashcode存取值的 ,当引用对象作为键值对集合中的键时,键值相等,但hashcode不相等,就没法获取“相等的”键所对应的值

import java.util.Hashtable;


public class TestHashCode {
	public static void main(String[] args) {
		Hashtable<HC,Integer> ht=new Hashtable<HC,Integer>();
		ht.put(new HC(1), 1);
		System.out.println(ht.get(new HC(1)));
		
		Hashtable<NHC,Integer> nht=new Hashtable<NHC,Integer>();
		nht.put(new NHC(1), 1);
		System.out.println(nht.get(new NHC(1)));
	}
}

class NHC{
	private int data;
	
	public NHC(int data) {
		this.data = data;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof NHC)
			return ((NHC)obj).data==this.data;
		return false;
	}
}

class HC{
	private int data;
	
	public HC(int data) {
		this.data = data;
	}
	
	@Override
	public int hashCode(){
		return data;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof HC)
			return ((HC)obj).data==this.data;
		return false;
	}
}

运行结果:

1
null

10.构造器是否创建了对象?构造器在实例化对象时起什么作用? 构造器并没有创建对象,而是new关键字创建了对象,构造器只是对对象初始化

11.静态方法是否可以重写?方法重写与方法隐藏有什么不同? 不可以,再调用子类的方法时,不知道是调用继承的方法,还是重写的方法 方法重写,更新方法的实现,是方法的替换 方法隐藏:在静态方法中,实现一个新方法,只是在类外无法调用原来的方法

(其实很容易理解,静态方法和属性都是放在静态存储区的,父类放父类的,子类放子类的,用的时候再从各自的存储区取得,各不相关)

public class TestStaticOverride {
	public static void main(String[] args) {
		System.out.println("Base class:");
		Base.T();
		
		System.out.println("Sub class:");
		new Sub();
		Sub.T();
	}
}

class Base{
	public static void T(){
		System.out.println("Hello,this is parent!");
	}
}

class Sub extends Base{
	public Sub(){
		super.T();
	}
	
	public static void T(){
		System.out.println("Hello,this is child!");
	}
}

可以看到在调用Sub.T()时,调用的是Sub的T()方法,但是并没有重写覆盖掉父类的方法,因为在Sub构造函数中调用父类T()方法时,依然生效

12.为什么不能在静态方法中使用this?this指代的当前对象在哪里? This对象,在对象被实例化、对象成员函数被调用的时候,虚拟机自动将该对象的引用作为隐藏参数传入构造器静态方法是类方法,this指代的是被实例化后的具体某个对象。静态方法在类的对象未被实例化时即可使用,此时尚未存在具体对象

13.在java中,类会在什么时间、什么条件下被jvm加载? 编译后形成.class文件,运行时被加载

14.Java中的枚举是怎么实现的? 枚举类型本质上是一个final类,继承自java.lang.Enum类 在枚举类型保持被枚举对象的引用,且用public static final进行修饰,这样外界就可以直接通过枚举类型.被枚举对象来访问该对象。

public abstract class Color extends java.lang.Enum(Color){     public static final Color RED;     public static final Color BLUE;     public static final Color WHITE; }

访问方式: Color.RED;

15.每个基本数据类型都对应一个包装类,这些包装类有什么作用? java是完全面向对象语言,所有数据都应该是对象,然而为了方便使用,设置了八个基本数据类型:byte、short、int、long、float、double、boolean、char 包装类是对这些基本数据类型的包装以实现面向对象的一些特性,包装类可以作为集合容器的key和value,基本数据类型不可以

16.内部成员类是如何绑定外围类对象的? 内部成员类中隐藏了一个外围对象的引用,在实例化的时候,自动将该引用指向实例化的外围类对象