Java面经集合(二)

1 Java语言的编译运行

Java语言号称一处编译,多处执行,但是Java语言并不是一种编译型语言,而是一种解释型语言。他的运行逻辑是,编译成一种特定的文件格式——字节码,在不同系统的机器中,只要有Java运行时环境(主要是解释器)就可以运行Java程序。
解释型虚拟机肯定比全速运行机器码要慢得多,但是Java虚拟机有一个选项,可以将执行比较频繁的字节码序列转换成机器码,这一过程称为即时编译,从而来提高程序的运行效率。

2 Java主函数

public static void main(String[] args){...}

Java运行编译后的程序的时候,虚拟机总是从指定类中的main方法开始执行的,因此为了能够执行,需要在所执行的类中添加main方法。
在Java1.4之前,存在一个bug,main方法不是public的也能在一些版本的解释器中执行,在1.4之后修复,强制main方法必须是public类型的。
main方法没有为操作系统返回“退出码”,如果正常退出,Java应用程序退出码为0,如果希望在终止程序时返回其他的返回码,需要使用System.exit方法。

System.exit(10);
输出
Process finished with exit code 10

main方法的参数
main方法在调用的时候可以传入参数,参数传入后存储在String数组中,在main函数中可以使用这些参数。

java Scratch 100 200

3 注释

Java中支持三种注释

  • 单行注释
    //注释内容,从注释内容开始,到本行结尾
  • 多行注释
    /*注释内容*/
  • 生成注释文档
    /**注释内容*/,该内容通常放在类前或方法前,用于生成api文档。

4 Java中的数据类型和控制语句

Java是一种强类型的语言,每一种变量必须声明一种数据类型。Java中只存在两种数据类型,一种是基本数据类型,有8种,除了8种基本数据类型之外,其他的都是引用数据类型。

4.1 八种基本数据类型

基本数据类型占用字节数取值范围
byte1-2^7 ~ 2^7-1
short2-2^15 ~ 2^15-1
int4-2^31 ~ 2^31-1
long8-2^63 ~ 2^63-1
float4IEEE754
double8IEEE754
char20~2^16-1
boolean1true or false

八种基本类型,其中整型四种,为byte,short,int,long。int为整型的默认类型,当byte、short、char与整型数字运算时,会自动提升成int值进行计算,返回的值也是int型。int型与long型计算会自动提升成long型。整型与浮点型计算会自动提升成double型。double是浮点型的默认类型,float定义时需要加f或F,否则被识别为double型。

byte b1 = 10;  //true
byte b2 = b1 + 10;  //false,编译报错,类型不匹配

byte与整型数字相加,会自动提升类型成int型,如果要在赋值给byte,需强转,但需考虑是否溢出。

char a = 'c';  //true
char b = a + 2;  //false,编译报错,类型不匹配
char c = -1; //false,编译拨错,类型不匹配
char d = '\u0041';  //true,使用Unicode形式定义,对应于A
char e = 65;  //true,对应于A
char f = '\101'; //true,对应于A,八进制表示

char值只有正值,存储字符,对应于Unicode编码值范围0~65535。如果给char值传入负值,会默认传入的为int值,导致类型不匹配编译报错。char存储Unicode编码字符串,可以使用Unicode编码进行初始化,如’\u0041’,‘\u’标识Unicode转义序列的开始,该值对应于’A’,其16进制为41,十进制为65,也可用其十进制值对char进行初始化。
除此之外,字符还可以使用八进制形式进行初始化,‘\nnn’,可表示0到255之间的Unicode值,前面的零可以省略,如’\41’。

float f1 = 0.02;  //false,默认成double
float f2 = 0.02f;  //true

浮点型定义默认成double型,所以定义float类型的浮点型,需要加f或F修饰。浮点数值的计算都遵循IEEE 754规范,有三个特殊的浮点数值表示溢出和出错情况:

  • 正无穷大
  • 负无穷大
  • NaN(非数字)
Double.POSITIVE_INFINITY
Double.NEGATIVE_INFINITY
Double.NaN

上面表示double类型的正负无穷和非数字,float类型也存在
非数字的检测不能使用==

if(x==Double.NaN) //is never true
应该使用
if(Double.isNaN(x)

浮点数不能应用于无法接受舍入误差的金融系统,因为计算机存储使用的是二进制,无法精确的表示小数。如果需要数值计算中无任何误差,则应该使用BigDecimal类。

int a = 2_014;

Java允许在数字中加入下划线来使之更容易阅读。

4.2 引用数据类型

Java中除了8种基本数据类型外,其他都是引用数据类型,包括数组、类、接口这些。

4.2.1 数组是类吗?

个人认为数组是一种特殊的类。
首先,我们知道数组是引用数据类型的,且基本数据类型的数组,并没有该类的存在。但是我们却可以打印数组的类名和父类名。

int[] arr = new int[10];
System.out.println(arr.getClass());
System.out.println(arr.getClass().getSuperclass());

输出结果为
class [I
class java.lang.Object

可以看到,我们打印了一下int数组的输出,可以获取类名和其父类。类名就是[I,其父类就是Object类。但是我们又找不到一个叫做[I的类,同时,数组在初始化的时候new int后面没有括号,说明没有调用任何的构造函数。一个可以获得类名,且有父类,但是又不实际存在的类,所以可以将其理解为一个特殊的类。

4.3 值传递和引用传递

对于基本数据类型,在调用方法时,传递参数使用的是值传递。形参是直接拷贝实参的值,在传入方法后,在方法中对于形参的操作都不会影响到实参。对于引用数据类型,传递的是引用,形参是实参引用的映射,他们指向了同一块内存空间,通过形参修改的是内存空间的值,所以从实参看来数据也是变化了的。

4.4 switch

switch支持byte、short、int、char。jdk7加入String。case必须是字符串常量或者字面量。

4.5 foreach

foreach是for在特殊时候的简化版本,并不能完全的替代for,因为不能获取到数组序号。foreach常用来遍历集合元素和数组。

5 Java中的修饰符

Java中的修饰符主要分为两类

  • 访问修饰符
  • 非访问修饰符

5.1 访问修饰符

访问修饰符本类同包子类其他包
private×××
default××
protected×
public

private私有访问权限,面向对象编程中封装的主要实现,将属性封装在类的内部,不暴露,只暴露公共的设置和获取接口给外部类使用。
default是默认访问权限,不添加权限修饰词,则是default访问权限。需注意的是在接口中和类中不同,接口中的变量默认是public static final类型的常量,方法默认是public类型的。
protected是保护类型的,对本包和其子类可见。不能用来修饰接口和类。保护不相关的类对该类的访问。
public是公有类型的,都可以进行访问。

  • 父类中为public的,子类重写也必须是public的
  • 父类中为protected的,子类中可以使protected或public的
  • 只有private不会被继承

5.2 非访问修饰符

  • static:静态修饰符,可用于修饰变量和方法,也可定义静态代码块。被static修饰的属于类,随着类的加载而初始化。静态的方法中只能调用静态元素,非静态的方法中既可以调用静态的元素,也可以调用非静态的元素。这是因为,非静态的方法调用依赖于对象,对象的创建晚于类的加载。static方法是不能重写的,同名的方法只是一个新的方法,跟父类的static方法无关,这是因为静态方法是属于类的。
  • final:可用于修饰类、成员变量和成员方法。final修饰的类不能够被继承;final修饰的成员变量值不能发生更改;final修饰的方法不能被重写,但是会被继承。
  • abstract:用于修饰抽象类或者抽象方法。拥有抽象方法的类必然是抽象类,但是抽象类不一定有抽象方法。子类必须重写所有的抽象方法,否则子类也必须声明为抽象的。抽象类不能实例化。不能被final和static修饰,因为final修饰的必须重写,与abstract冲突。
  • synchronized:同步修饰符,会加互斥锁。
  • transient:修饰成员变量,修饰后的不会被序列化。
  • volatile:被该修饰符修饰的变量,读取时都从共享内存中读取,写入时会立即同步到共享内存中,保证可见性。

6 类和对象

6.1 变量类型

  • 局部变量:定义在方法中的变量,作用域只在方法中
  • 成员变量:定义在类中,方法外的变量。属于对象,类每初始化一个对象,就会存在一个该变量。
  • 类变量:定义在类中,方法外,用static修饰的变量。随着类的初始化而初始化,属于类,所有对象共享该变量。
    被final声明的变量为常量,第一次赋值后值不可更改。但是对于引用数据类型,指的是指向的变量是一个变量,他的地址不更改,但是地址中的内容是可以更改的。
    成员变量和类变量会自动进行初始化,赋值为默认的值,其中整型为0,char为空字符,引用类型为null。
	int a;
    static char b;
    static double c;
    static byte d;
    static String str;
    public static void main(String[] args) {
        Scratch scratch = new Scratch();
        System.out.println(scratch.a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
        System.out.println(str);
    }
输出
0
 
0.0
0
null

声明一个局部变量后,必须用赋值语句对变量进行显示的初始化后才能使用该变量。
Java10开始,对于局部变量,如果可以从变量的初始化值推断出它的类型,就不再需要声明类型。只需要使用关键字var让其自行推断。

	var number = 12;
    var str = "hello";
字节码文件中的
	boolean var1 = true;
    String var2 = "hello";

可以看到编译成字节码文件后,编译器自动将其转化为了特定的实际类型,因为java是强类型语言,需要有实际的数据类型,编译器对其推断后更改为了特定类型。

6.2 构造函数

  • 每个类都有构造函数,如果没有定义构造函数,编译器会为该类提供一个默认的构造函数。
  • 子类会在构造函数的第一行调用父类的构造函数,如果没有定义,会提供一个隐藏的super调用父类的无参构造函数。如果父类没有无参构造函数,则子类必须显示的调用父类的有参构造函数,否则会报错。这是因为在子类初始化之前必须先初始化父类。
  • 构造函数是一个没有返回值类型的函数。
  • 可以通过this调用本类的其他构造函数。
  • 构造函数可私有,私有构造函数后,不能在其他地方创建该类对象。

6.3 源文件声明规则

  • 一个源文件只能有一个public类
  • 一个源文件可以有多个非public类,每个类都会生成一个对应的class文件
  • 源文件的名字应与public类名相同
  • 包名放在首行
  • import导入放在包名和类名之间
  • package和import作用于整个源文件的类

7 Java中参数传递

7.1 类名作为形参和返回值

  • 类名作为参数
    方法的形参是类名,传入的是该类的对象,实际传递的是对象的地址。
  • 类名作为返回值
    返回值是类名,返回的是该类的对象,传递的也是对象的地址。

7.2 抽象类作为形参和返回值

  • 抽象类作为参数
    方法的形参是抽象类类型的,传入的应该是抽象类的子类对象,因为抽象类是不能实例化的。
  • 抽象类作为返回值
    返回值是抽象类类型的,返回的是抽象类的子类对象。

7.3 接口作为形参和返回值

  • 接口类型作为参数
    接口类型作为参数,传入的是实现类的对象,因为接口不能实例化。
  • 接口类型作为返回值
    返回值是接口类型的,返回的是接口的实现类对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值