###################java基础回顾#############

1.float类型在Java中占用4字节,long类型在Java中占用8字节,为什么float类型的取值范围比long类型的取值范围还大?

我们都知道,float类型的范围是:一3.403E38~3.403E38。而long类型的范围是:-2^63~2^63-1(大概是9*10^18)。 而float在内存中占4个字节,共32位,但是浮点数在内存中是这样的:  V=(-1)^s * M * 2^E       浮点数的32位不是简单的直接表示大小,而是按照一定的标准分配的。
  其中第1位,符号位,即S。
  接下来的8位,指数域,即E。
  剩下的23位,小数域,即M,M的取值范围为[1,2)或[0,1)。
  也就是说,浮点数在内存中的二进制值不是直接转换为十进制数值的,而是按照上述公式计算而来,通过这个公式,虽然只用到了4个字节,但是浮点数却比长整型的最大值要大。
  这也就是为什么在数据转换的时候,long类型转换为float类型的根本原因所在!
 

2.使用“+”可以连接两个字符串(String对象),那么,是怎样进行连接的?

在执行+的时候,实际上是将该string名字指向了另外一个字符串,这样在执行多次+的时候就会浪费资源.
 

3.构造器是否创建了对象?该怎样来证明这一点?

当系统开始执行构造器的构造体之前,系统已经创建一个对象,只是这个对象还不能被外部程序访问,只能在该构造器中通过this来引用。当构造器的执行体执行结束后,这个对象作为构造器的返回值被返回,通常还会赋给另一个引用变量,从而让程序外部可以访问该对象。单例啊,工厂之类的
 

4.如果没有在类中显示声明构造器,则编译器会自动生成一个无参的构造器,那么编译器为什么要自动生成这个无参的构造器呢?有什么作用?

如果父类未提供无参构造器,子类会报错;如果构造器中添加了this引用该类的其他构造器,或者添加了super()调用父类构造器,this和super必须在构造器第一行,this引用其他构造器和super()语句不会同时出现 ;如果构造器中添加了this引用该类的其他构造器,或者添加了super()调用父类构造器,如果this和super中有参数,则只能是静态的方法和静态变量或常量
 

5.i++与++i到底有什么不同?仅仅是先加与后加的区别吗?

++i是先自加1,然后再赋值i++是先赋值,再加1
i++ 语句需要个临时变量,去存储返回自增前的值。

不要忽略这个变量的意义,了解过 C 等“低级”语言的朋友,可能会了解变量的内部机制(重新祭奠我老去的 C 语言知识)。首先,申请(malloc)一段内存空间,然后将值塞(push,压栈)进去,最后不用了释放(free)。

大家可能在循环中会经常的使用 i++ 这样的操作。在不影响逻辑的前提下,我建议使用 ++i ,虽然这点的优化非常的小
 

6.移位运算:5 << 35,会首先进行35 % 32的求余运算吗?如果是这样,那么5 << −2的结果是多少呢?

2^30  -2即视为0xFFFE(补码)。会位移0xFFFE mod 32 = 30位
 

7.如果重写了equals方法,为什么还要重写hashCode方法?如果没有重写hashCode方法,会有什么问题?

object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址

hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。
 

8.从JDK1.7起,switch语句可以支持String类型,那么在底层是如何实现的?

在编译器层次实现的含义是,虽然开发人员在Java源代码的switch语句中使用了字符串类型,但是在编译的过程中,编译器会根据源代码的含义进行转换,将字符串类型转换成与整数类型兼容的格式。不同的Java编译器可能采用不同的方式来转换,并采用不同的优化策略。比如:如果switch语句中只包含一个case语句,那么就可以简单的将其转换成一个if语句。如果包含一个case和一个default语句,就可以转换成if-else语句。而对于复杂的情况(多个case语句),也可以转换成Java 7 之前的switch语句,只不过使用字符串的哈希值作为switch语句表达式的值。经过转换,Java 虚拟机看到的仍然是与整数类型兼容的类型。这里要注意的是,在case字句中对应的语句块中仍然需要使用String的equals方法来进行字符串比较,这是因为哈希函数在映射的时候可能存在冲突,这样更加保险了。

 

9.静态方法是否可以重写?方法重写与方法隐藏有什么不同?

"重写"只能适用于实例方法.不能用于静态方法.对于静态方法,只能隐藏(形式上被重写了,但是不符合的多态的特性),“重写”是用来实现多态性的,只有实例方法是可以实现多态,而静态方法无法实现多态。
 

10.为什么不能在静态方法中使用this?this指代的是当前对象,但是,这个所谓的“当前对象”到底在哪里?

因为this代表的是调用这个函数的对象的引用,而静态方法是属于类的,不属于对象,静态方法成功加载后,对象还不一定存在。所有的成员方法,都有一个默认的的参数this(即使是无参的方法),只要是成员方法,编译器就会给你加上this这个参数。而静态方法与对象无关,根本不能把对象的引用传到方法中,所以不能用this。
 

11.在Java中,类型会在什么时间、什么条件下由JVM加载?加载后一定会初始化吗?不一定

贴张图
研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行。
研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性。
把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析、初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
下面是会对类进行初始化的情况:
1、当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
2、当调用某个类的静态方法时
3、当使用某个类或接口的静态字段时
4、当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时
5、当初始化某个子类时
6、当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)
Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:clinit。
Class.forName("A")相当于Class.forName("A",true,this.getClass().getClassLoader()) true参数代表对类A进行初始化。

Class.forName("A",false,this.getClass().getClassLoader()) 就不会对类A进行初始化了。
ClassLoader的loadClass(String className);方法只会加载并编译某类,并不会对其执行初始化。
 

12.比起C / C++中的枚举,Java中的枚举有什么不同(优势)?枚举是怎样实现的?

简单说:枚举可以限定取值范围,所有的内容只能从指定范围中取得.
比如性别,只有男和女,其他值都是不合法的
如果不用枚举也可以构造这样的方法,但可能要做更多的工作,也可能不安全
但运用枚举,就可以避免这些问题了
Java枚举和C++枚举的主要区别为两点,一是C++中的枚举中只能定义常量,主要用于switch子句,二是C++中的枚举常量可以直接和数值型变量进行各种数学运算。java枚举要广泛点。
 

13.为什么要为String对象建立常量池?String常量池有什么好处?

常量池就类似一个JAVA系统级别提供的缓存。
8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种:
1)直接使用双引号声明出来的String对象会直接存储在常量池中。
2)如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
     1.单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
  2,使用new String("")创建的对象会存储到heap中,是运行期新创建的;
  3,使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
  4,使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
用new创建的每new一次就在堆上创建一个对象,用引号创建的如果在常量池中已有就直接指向,不用创建
 

14.每个基本数据类型都对应一个包装类型,这些包装类型有什么用?

Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便
对于包装类说,这些类的用途主要包含两种:
a、作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。
b、包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。
 

15.内部成员类是如何绑定外围类对象的?

在内部类中之所以能直接调用外部类的方法,是因为在内部类中隐藏了 : 外部类名.this。

但在外部类中调用内部类的成员时必须要创建内部类的对象,因为没有:内部类.this。
我们知道有这个引用,知道有这么回事就行了。没有必要知道怎么调用这个引用。

16.文件类File

 mkdir(),mkdirs(),createNewFile()的区别 
* createNewFile:新建文件(非目录) 
* mkdir:新建目录 
* mkdirs:新建目录,与mkdir的区别是:比如 mkdirs(“D:/test/test2”) 如果test , 不存在会创建,然后创建test2,如果是 mkdir(“D:/test/test2”) ,如果 test不存在,会失败。 
* android io输入文件

new File(param1,param2); param1 File,param2  String类型

 String dir = StorageUtils.getCacheDirectory(this);
 String apkDIR = "apkdir.apk";
File apkFile = new File(dir, apkDIR);

17.为什么接口中只能定义static final:

    static(这时暂且认为是变量)解释:因为一个类可以实现多个接口,如果一个类同时实现了多个接口而每个接口中都定义了同一个变量的话就会产生在类中不知道是哪个接口中的变量了,所以必须定义成static的,每个接口拥有各自的这个变量。

    final解释:因为一个接口可以被多个类实现,如果不定义成final的话每个实现了该接口的类都去改变这个变量就会产生错误,所以必须定义成final。

18.为什么抽象类中可以定义变量:

    因为每个类只能有一个父类,就不会产生上述的接口中的一些问题。

抽象类:
1) 抽象方法,只有行为的概念,没有具体的行为实现。使用:abstract 关键字修饰,并且没有方法体。
2) 包含抽象方法的类,就一定是抽象类。使用: abstract 关键字修饰,包含抽象方法。
3) 抽象类不能直接创建实例。可以定义引用变量。
4) 抽象类只能被继承,一个具体类继承一个抽象类,必须实
现所有抽象方法。
5) 抽象方法和抽象类非常适合作为系统的分析和设计的工具。
接口:
1 接口:全部的方法都是抽象方法,全部的属性都是常量。接口用来表示纯抽象概念,没有任何具体的方法和属性。
2 不能实例化,可以定义变量。
3 接口变量可以引用具体实现类的实例。
4 接口只能被实现(继承),一个具体类实现接口,必须使用全部的抽象方法。
5 接口之间可以继承。
6 一个具体类可以实现多个接口,实现多继承现象,表示:C++的多重继承
7 接口中的属性,默认是常量 public static final
8 接中的方法一定是:public abstract
9 实现一个接口,使用关键字implements, 实现实际上是一种继承关系。接口和实现类是父子类型的关系
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值