Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE

文章目录

    • 一、基本数据类型
      • 1.1 整型数据
      • 1.2 浮点型数据
        • 1.2.1 浮点型数据介绍
        • 1.2.2 浮点型数据引起的运算误差怎么解决
      • 1.3 布尔型数据
      • 1.4 字符型数据
      • 1.5 显式转换与隐式转换
        • 1.5.1 隐式转换
        • 1.5.2 显式转换
      • 1.6 隐式转换中需要注意的问题
        • 1.6.1 整型数据运算时的特殊情况
        • 1.6.3 隐式转换相关的建议
    • 二、变量类型
      • 2.1 局部变量
      • 2.2 实例变量
      • 2.3 类变量/静态变量
    • 三、修饰符
      • 3.1 访问修饰符
      • 3.2 非访问修饰符
    • 四、表达式
      • 4.1 算术运算符
      • 4.2 关系运算符
      • 4.3 位运算
      • 4.4 逻辑运算符
      • 4.5 赋值运算符
      • 4.6 条件运算符
      • 4.7 instanceof运算符
        • 4.7.1 obj 必须为引用类型,不能是基本类型
        • 4.7.2 obj为null时的情况
        • 4.7.3 obj为类的实例对象的情况
        • 4.7.4 obj为class接口的实现的情况
        • 4.7.5 obj为class 类的直接或间接子类的情况
        • 4.7.6 instanceof运算符的实现
      • 4.8 运算符优先级比较
    • 五、数组
      • 5.1 声明数组
      • 5.2 创建数组
      • 5.3 遍历数组
      • 5.4 数组复制
    • 六、工具类
      • 6.1 Math类
        • 6.1.1 三角函数类方法
        • 6.1.2 数值计算类方法
      • 6.2 Arrays类
      • 6.3 Collections类
    • 七、分支循环
      • 7.1 分支结构
      • 7.2 循环结构
      • 7.3 跳转语句
    • 八、关键字与标识符
      • 8.1 所有关键字
      • 8.2 部分重要关键字
        • 8.2.1 abstract
        • 8.2.2 final
        • 8.2.3 static
        • 8.2.4 super
        • 8.2.5 this
      • 8.3 标识符
    • 九、传值调用和传引用调用
      • 9.1 两者定义
      • 9.2 传参举例
        • 9.2.1 传值调用
        • 9.2.2 传引用调用
      • 9.3 传参总结
    • 十、BS架构和CS架构
      • 10.1 BS、CS架构定义
      • 10.2 BS、CS架构的优缺点
    • 十一、Java SE/Java EE/Java ME
    • 十二、 JDK与JRE
    • 十三、 简单编程规范的判断

  本系列文章共分为五篇:
    Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE
    Java基础知识(二)字符串、Java常用包、四种引用、内存泄漏、深克隆与浅克隆、IO、语法糖
    Java基础知识(三)面向对象、类和对象、封装继承多态、重写和重载、构造方法、内部类、包装类、对象实例化的四种方式
    Java基础知识(四)异常、final/finally/finalize、可变参数、枚举、日期、反射、泛型
    Java基础知识(五)网络编程、lambda表达式、Stream、自定义注解

  Java语言的特点:

  1. 跨平台性
      在Java语言中, Java自带的虚拟机很好地实现了跨平台性。 Java源程序代码经过编译后生成二进制的字节码是与平台无关的,但是可被Java虚拟机识别的一种机器码指令。 Java虚拟机提供了一个字节码到底层硬件平台及操作系统的屏障,使得Java语言具备跨平台性。
  2. 面向对象
      Java是面向对象的语言,使用面向对象的思想,可以降低程序耦合度,提高内聚性。
  3. 安全性
      安全性可以分为四个层面,即语言级安全性、编译时安全性、运行时安全性、可执行代码安全性。语言级安全性指Java的数据结构是完整的对象,这些封装过的数据类型具有安全性。编译时要进行Java语言和语义的检查,保证每个变量对应一个相应的值,编译后生成Java类。运行时Java类需要类加载器载入,并经由字节码校验器校验之后才可以运行。
  4. 多线程
      多线程可以提高程序的运行效率。
  5. 简单易用,有丰富类库
      简单易用指的是Java程序的开发不必非得依赖特定的开发环境,用notepad等文本编辑工具就可编译。有丰富类库的意思是便于开发者开发多种多样的功能。

一、基本数据类型

  Java中,变量的目的是申请内存来存储值。也就是说,当一个变量被创建时,就需要在内存中申请空间,内存管理系统根据变量的类型为变量分配相应的存储空间,此时分配的空间只能用来存储该类型数据。
  Java有两大数据类型:

1>内置数据类型
2>引用数据类型

  Java中,共有八种基本类型:六种数字类型(四整型,二浮点型),一种字符类型,一种布尔类型。

1.1 整型数据

  整形数据分为4种:
   1>byte
    8位,有符号整数,范围为-27 ~ 27-1,默认值是0。
   2>short
    16位,有符号整数,范围为-215 ~ 215-1,默认值是0。
   3>int
    32位,有符号整数,范围为-231~ 231-1(约-21亿 ~ 21亿),默认值为0,一般整型变量默认为int型。
   4>long
    64位,有符号整数,范围为-263 ~ 263-1,默认值为0L。赋予long型变量初始值时,需要在数字后面加上L。
  测试代码如下:

	static byte b1;
	static short s1;
	static int i1;
	static long l1;
	public static void main(String[] args){
     
        System.out.println("byte型变量默认值 :"+b1 );
        System.out.println("short型变量默认值 :"+s1 );
        System.out.println("int型变量默认值 :"+i1 );
        System.out.println("long型变量默认值 :"+l1 );
	}

  测试结果:

byte型变量默认值 :0
short型变量默认值 :0
int型变量默认值 :0
long型变量默认值 :0

  在进行整型数据运算时,要注意溢出的问题,比如以int型为例,Integer.MAX_VALUE+1的运算结果是Integer.MIN_VALUE

1.2 浮点型数据

1.2.1 浮点型数据介绍

 浮点型数据分为2种:

  1. float
      单精度,32位,默认值是0.0f。
  2. double
      双精度,64位,默认值是0.0d,浮点型变量默认为double型

  测试代码如下:

	static float f1;
	static double d1;
	public static void main(String[] args){
     
        System.out.println("float型变量默认值 :"+f1 );
        System.out.println("double型变量默认值 :"+d1 );
	}

  测试结果:

float型变量默认值 :0.0
double型变量默认值 :0.0

1.2.2 浮点型数据引起的运算误差怎么解决

  先看一个例子:

		System.out.println(0.06+0.01);
		System.out.println(2.0-1.1);
		System.out.println(3.3*3);
		System.out.println(3.3/3);

  在我们的想象中,这4个语句的执行结果应该是0.07、0.9、9.9、1.1,但是事实却不是这样的,实际的结果是:

0.06999999999999999
0.8999999999999999
9.899999999999999
1.0999999999999999

  从这个例子可以看出,其实浮点数的计算是可能不准确的,引用网上的一段话,float和double类型的使用局限:
   1)单精度浮点型变量float可以处理6 ~ 7位有效数,双精度浮点型变量double可以处理15~16位有效数,在实际应用中,如果需要对更大或者更小的数进行运算和处理,这时候float和double就无能为力了。
   2)float和double类型的主要设计目标是为了科学计算和工程计算,他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。
  商业计算往往要求结果精确,这时候就需要用到BigDecimal。BigDecimal的使用,示例如下:

public class DoubleTest {
     
	
	public static void main(String[] args)  {
     
		System.out.println(add(0.06,0.01));
		System.out.println(subtract(2.0,1.1));
		System.out.println(multiply(3.3,3));
		System.out.println(divide(3.3,3,1));
	}
	/* 加法运算*/
	public static double add(double x, double y) {
     
		BigDecimal vala = new BigDecimal(Double.toString(x));
		BigDecimal valb = new BigDecimal(Double.toString(y));
		return vala.add(valb).doubleValue();
	}
	
	/*减法运算*/
	public static double subtract(double x, double y) {
     
		BigDecimal vala = new BigDecimal(Double.toString(x));
		BigDecimal valb = new BigDecimal(Double.toString(y));
		return vala.subtract(valb).doubleValue();
	}
	
	/*乘法运算*/
	public static double multiply(double x, double y) {
     
		BigDecimal vala = new BigDecimal(Double.toString(x));
		BigDecimal valb = new BigDecimal(Double.toString(y));
		return vala.multiply(valb).doubleValue();
	}
	
	/*除法运算(结果进行四舍五入)*/
	public static double divide(double x, double y, int scale) throws ArithmeticException {
     
		if (scale < 0) {
     
			throw new ArithmeticException("精确度不能小于0");
		}
		
		BigDecimal vala = new BigDecimal(Double.toString(x));
		BigDecimal valb = new BigDecimal(Double.toString(y));
		return vala.divide(valb, scale, BigDecimal.ROUND_HALF_EVEN).doubleValue();
	}
}

  此时的结果就和我们预想的一致了,如下:

0.07
0.9
9.9
1.1

1.3 布尔型数据

  boolean,1位,只有两个取值:true和false,默认值是false。
  测试代码如下:

	static boolean b1;
	public static void main(String[] args){
     
        System.out.println("boolean型变量默认值 :"+b1 );
	}

  测试结果:

boolean型变量默认值 :false

1.4 字符型数据

  char,16位Unicode字符,范围为0 ~ 215-1(\u0000到\uffff),可存储任意字符,默认值是’u0000’。
  一个char类型变量中可以存储一个中文汉字,因为char类型变量使用的默认编码格式是 Unicode,一个 char 类型占 2 个字节(16 比特),所以放一个中文是没问题的。
  每种数据类型的取值范围可以通过其包装类来查看,如下:

类型 位数 最大值 最小值
byte Byte.SIZE Byte.MAX_VALUE Byte.MIN_VALUE
short Short.SIZE Short.MAX_VALUE Short.MIN_VALUE
int Integer.SIZE Integer.MAX_VALUE Integer.MIN_VALUE
long Long.SIZE Long.MAX_VALUE Long.MIN_VALUE
float Float.SIZE Float.MAX_VALUE Float.MIN_VALUE
double Double.SIZE Double.MAX_VALUE Double.MIN_VALUE
char Character.SIZE Character.MAX_VALUE Character.MIN_VALUE

  测试代码如下:

        System.out.println("byte型变量位数:"+Byte.SIZE+",byte型变量最大值:"+Byte.MAX_VALUE+",byte型变量最小值:"+Byte.MIN_VALUE );
        System.out.println("short型变量位数:"+Short.SIZE+",short型变量最大值:"+Short.MAX_VALUE+",short型变量最小值:"+Short.MIN_VALUE );
        System.out.println("int型变量位数:"+Integer.SIZE+",int型变量最大值:"+Integer.MAX_VALUE+",int型变量最小值:"+Integer.MIN_VALUE );
        System.out.println("long型变量位数:"+Long.SIZE+",long型变量最大值:"+Long.MAX_VALUE+",long型变量最小值:"+Long.MIN_VALUE );
        System.out.println("float型变量位数:"+Float.SIZE+",float型变量最大值:"+Float.MAX_VALUE+",float型变量最小值:"+Float.MIN_VALUE );
        System.out.println("double型变量位数:"+Double.SIZE+",double型变量最大值:"+Double.MAX_VALUE+",double型变量最小值:"+Double.MIN_VALUE );
        System.out.println("char型变量位数:"+Character.SIZE+",char型变量最大值:"+Character.MAX_VALUE+",char型变量最小值:"+Character.MIN_VALUE );

  测试结果:

byte型变量位数:8,byte型变量最大值:127,byte型变量最小值:-128
short型变量位数:16,short型变量最大值:32767,short型变量最小值:-32768
int型变量位数:32,int型变量最大值:2147483647,int型变量最小值:-2147483648
long型变量位数:64,long型变量最大值:9223372036854775807,long型变量最小值:-9223372036854775808
float型变量位数:32,float型变量最大值:3.4028235E38,float型变量最小值:1.4E-45
double型变量位数:64,double型变量最大值:1.7976931348623157E308,double型变量最小值:4.9E-324
char型变量位数:16,char型变量最大值:,char型变量最小值:

  char类型比较特殊,Character.MAX_VALUE的值是’\uFFFF’;MIN_VALUE的值是’\u0000’。
  包装类还可以用来实现基本数据类型之间的转换,每个包装类中总有xxValue方法,来获得其对应的简单数据类型。
  String不是Java的基本数据类型,默认值为null
  其他数据类型转换为String的方式:

  1. X.toString()
  2. X+""
  3. String.valueOf(X)

  此处以int型数据转换为String为例,测试代码如下:

		Integer i1 = 1;
		String str1 = i1.toString();
		String str2 = i1+"";
		String str3 = String.valueOf(i1);
		System.out.println(str1+","+str2+","+str3);

  测试结果:

1,1,1

  String数据转换为其他简单类型的方式:
   1>包装类的xxValue(),比如:Double.valueOf(“32.1”).doubleValue()。
   2>包装类的静态parseXX方法,比如:Double d = Double.parseDouble(s)。
  Java中,任何类型与字符串相加,都是进行拼接。原理为:先用String.valueOf()方法,再通过StringBuilder进行拼接
  此处以int型数据转换为String为例,测试代码如下:

		String str1 = "123";
		int i1 = Integer.valueOf(str1).intValue();
		int i2 = Integer.parseInt(str1);
		System.out.println(i1+","+i2);

  测试结果:

123,123

  Java中,引用类型的变量类似于C/C++中的指针,引用类型指向一个对象,指向对象的变量是引用变量。引用变量在声明时被指定为一个特定类型,并且不允许更改。
  对象、数组是引用数据类型,引用类型的默认值是null。
  final修饰常量,为了便于识别,一般用大写字母表示。
  Java常用转义字符:

符号 \n \r \f \b \0 \s \t " \
意义 换行 回车 换页 退格 空字符 字符串 制表符 双引号 单引号 反斜杠

1.5 显式转换与隐式转换

  Java中,整型、常量、字符型数据可以混合运算。不同类型的数据进行运算时,会先转换为同一类型(更高的数据类型),再进行运算。
  各变量优先级如下:
    低 ----------------------------------------------------> 高
    byte,short,char—> int —> long—> float —> double
  在8种基本数据类型中,char是比较特殊的一种类型,一共有2的16次方个数值。char如果char类型转成byte,short类型的时候,需要强转。示例如下:

		char num1 = 1;
		int num2 = num1;
		double num3 = num1;
		short num4 = num1; //编译报错
		byte num5 = num1;  //编译报错	

  再用个更清晰的图来表示的话,如下:
Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE_第1张图片
  数据类型转换时需要注意的规则:
   1>不能对boolean类型进行类型转换。
   2>把优先级高的转换为优先级低时必须使用强制类型转换。
   3>转换过程中可能导致溢出或损失精度。

  自动类型转换发生在转换前的数据类型的位数低于转换后的数据类型。
  强制类型转换发生的条件是转换前后的数据类型必须是兼容的。
  强制类型转换的格式为:(type)value。
  类型转换可分为两种:隐式转换和显式转换。

1.5.1 隐式转换

   从表示范围小的类型转换为表示范围大的类型,可以直接转换,称为隐式转换。示例如下:

		short m = 912;
        int n = m;

   因为int可以存储的范围要比short存储的范围大,所以short类型可以直接转换成int类型。

1.5.2 显式转换

   从表示范围大的类型转换为表示范围小的类型,需要强制转换,称为显式转换。示例如下:

		double m = 9.12;
        int n = (int)m;
        System.out.println(n); //9

  从该例子可以看出,显式转换可能伴随着精度的丢失

1.6 隐式转换中需要注意的问题

  在使用+=、-=等符号时,常常伴随着隐式类型转换的进行,如果参与运算的两个变量数据类型相同,一般不会有什么问题。如果两个变量数据类型不同,就需要注意一些潜在的问题了。

1.6.1 整型数据运算时的特殊情况

  先看如下代码存不存在问题:

        byte a=1;
        a=a+4;
        System.out.println(a);

  上面代码粗看上去,好像没什么问题,实则不是。在执行语句’a=a+4’时,a是byte类型,而数字4默认是int 类型。在java中,在a+4时,会进行 自动类型转换 ,所以a+4 会转换成int类型。而变量a还是byte类型,将int 类型的a+4赋值给byte类型的a ,无疑会报错。
  此时如果要消除错误,可以使用强制类型转换,示例如下:

        byte a=1;
        a=(byte)(a+4);
        System.out.println(a);

  也可以用如下方法修改:

        byte a=1;
        a+=1;
        System.out.println(a);

  依然先看如下代码存不存在问题:

		byte a = 127;
		byte b = 0;
		b = a + b; 

  粗看之下好像也没问题,其实也有问题,报错如下:
Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE_第2张图片
  此时建议将上述代码,修改为如下形式:

		byte a = 127;
		byte b = 0;
		a += b; 

  上面现象产生的原因是:整型数据和整型数据进行运算的时候,如果两边的值都是小于或者等于int的,那么其结果就是int型
  此外还有一种情况,先看下面代码:

		int a = 0;
		long b = 10L;

  a + b 的结果是long型,原因是:整型数据和整型数据进行运算的时候,如果有一边的长度超过int,那么运算结果就按照最长的长度

1.6.3 隐式转换相关的建议

  当操作的变量涉及非int型变量时,建议使用'a += b',不用'b = a + b'

二、变量类型

  Java中的变量类型大致可分为3种:

  1. 类变量,方法体之外的变量,用 static 修饰。
  2. 实例变量,方法体之外的变量,无 static 修饰。
  3. 局部变量:方法体中的变量。

2.1 局部变量

  局部变量的特征:
   1>声明在方法、构造方法或者语句块中。
   2>在方法、构造方法、或者语句块被执行的时候创建,执行完后,变量将会被销毁。
   3>只在声明它的方法、构造方法或者语句块中可见,访问修饰符不能用于局部变量
   4>所占用的内存空间在栈。
   5>没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

2.2 实例变量

  实例变量的特征:
   1> 声明在一个类中,但在方法、构造方法和语句块之外。
   2>当一个对象被实例化之后,每个实例变量的值就跟着确定。
   3>实例变量在对象创建的时候创建,在对象被销毁的时候销毁。
   4>访问修饰符可以修饰实例变量。
   5>实例变量对于类中的方法、构造方法或者语句块是可见的。
   6>实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。
   7>实例变量可以直接通过变量名访问。

2.3 类变量/静态变量

  静态变量的特征:
   1>在方法体之外,用static关键字声明。
   2>静态变量的数量与该类创建的对象数量无关,只有一个。
   3>静态变量储存在静态存储区。
   4>静态变量在第一次被访问时创建,在程序结束时销毁。
   5>默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。
   6>可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
类变量被声明为public static final类型时,类变量名称一般建议使用大写字母,此时的作用就是与常量相同。
  静态变量与实例变量的区别:
   1>静态变量属于类,该类不生产对象,通过类名就可以调用静态变量。
   2>实例变量属于该类的对象,必须产生该类对象,才能调用实例变量。

三、修饰符

  Java中修饰符主要分为:访问修饰符和非访问修饰符。

3.1 访问修饰符

  顾名思义,该类修饰符重要控制访问权限。不同修饰符的修饰对象,大致如下:
   1>default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
   2>private : 在同一类内可见。使用对象:变量、方法。
   3>protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。
   4>public : 对所有类可见。使用对象:类、接口、变量、方法。
  不同修饰符的访问范围,如下:

修饰符 当前类 同包类 子类 其他类
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N

  接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
  声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private。也就是说,声明为private的方法和变量,都是当前类内部使用的,外部不能访问。
  protected特征:
   1>子类与基类在同一包中,被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问。
   2>子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。
  访问控制和继承规则:
   1>父类中声明为 public 的方法在子类中也必须为 public。
   2>父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
   3>父类中声明为 private 的方法,不能够被继承。
  这三条规则体现的访问权限放大机制,即子类方法的方法访问权限>=父类的方法访问权限
  关于private、default、protected、public四种修饰符在平时开发中的使用,不太知道怎么使用的话,可以简单参考以下几条原则:
   1>属性通常使用private封装起来
   2>方法一般使用public用于被调用
   3>会被子类继承的方法,通常使用protected
   4>作用范围最小原则。即能用private就用private,不行就放大一级,用default,再不行就用protected,最后用public, 这样就能把数据尽量的封装起来

3.2 非访问修饰符

 非访问修饰符,主要有static、final、abstract。

  1. static
      static修饰变量,就是静态变量,一个类只有一个静态变量。
      static修饰方法,通过类名而不是该类实例化的对象调用。
  2. final
      final修饰变量,声明的时候必须初始化,不能被修改。
      final修饰方法,可以被子类继承,但是不能被子类重写。
      final修饰类,不能被继承。
  3. abstract
      abstract修饰类,不能被实例化。
      abstract修饰方法,需要被子类重写,除非子类也是抽象类。

四、表达式

  Java表达式是变量、常量、运算符、方法调用的序列,执行指定的计算并返回特定的值。
  表达式一般是按运算符来划分的,表达式种类如下:

1>算术表达式
2>关系表达式
3>布尔逻辑表达式
4>位运算表达式
5>赋值表达式
6>条件表达式

4.1 算术运算符

  + - * / % ++ –
  a++代表先使用,再+1,;–a代表先减1,再使用。测试代码如下:

		for(int i=0;i<3;i++){
     
			System.out.println(i);
		}

  测试结果:

0
1
2

  由这个例子可以看出,i++这种自增或自减符号在运算表达式或变量后面的,是先使用,再变化。

4.2 关系运算符

  == != > < >= <=
  关系运算符比较的都是值,而非引用。

4.3 位运算

  位运算应用于char、short、int、long型数据。
  位运算方式:
   1>&,都为1,结果则为1,否则为0。
   2>|,都为0,结果为0,否则为1。
   3>^,相同为0,不同为1。
   4>~,取反。
   5> <<,按位左移运算符,乘2的n次方。
   6> >>,按位右移运算符,除2的n次方。

4.4 逻辑运算符

  逻辑运算有三种:
   1>&&,逻辑与运算,都为真结果则为真。
   2>||,逻辑或运算符,有真则为真。
   3>!,逻辑非运算符,取反。
  &&为短路逻辑与运算符,即前面的判断条件为false时,不再进行后面条件的判断。
  ||为短路或运算符,即如果左边的运算结果已经是true,右边的语句不会再执行。
  关于短路功能,测试代码如下:

		int i=1;
		if(i==2 && (i++)==2)
			System.out.println("test");
		System.out.println("i:"+i);

  测试结果:

i:1

  由这个例子可以看出:当&&前面的判断条件i==2不成立时,后面的判断语句也没有进行

4.5 赋值运算符

  = += -= *= /= %= <<= >>= &= ^= |=
  特殊赋值运算符(如:+=)可以在不改变原有数据类型的情况下实现运算,如果两个值数据类型不一致,会进行强制数据类型转换。测试代码如下:

		int i=1;
		i+=2;
		System.out.println("i:"+i);
		i+=2.0f;
		System.out.println("i:"+i);

  测试结果:

i:3
i:5

4.6 条件运算符

  即三元运算符,形式为:x = (expression) ? trueVal : falseVal。测试代码如下:

		int gradeA=98;
		int gradeB=93;
		int betterGrade=0;
		betterGrade=gradeA>gradeB?gradeA:gradeB;
		System.out.println("两个同学中较好的成绩是:"+betterGrade);

  测试结果:

两个同学中较好的成绩是:98

4.7 instanceof运算符

  此处借鉴网上的一篇博客:Java关键字(一)——instanceof
  instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

	boolean result = obj instanceof Class

  其中obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
  此处需要注意的是:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

4.7.1 obj 必须为引用类型,不能是基本类型

  instanceof 运算符只能用作对象的判断,所以下面两种写法都会编译报错:

		int i = 0;
		System.out.println(i instanceof Integer);
		System.out.println(i instanceof Object);

4.7.2 obj为null时的情况

  Java中,数据分为基本数据类型和引用数据类型,null不属于这两种类型,自然不能算作引用类型。因此,在JavaSE中对 instanceof 运算符的规定就是:如果 obj 为 null,那么将返回 false。即下面的写法,会返回false

	System.out.println(null instanceof Integer);

4.7.3 obj为类的实例对象的情况

  这是最常用的情况,示例如下:

		Integer integer = new Integer(1);
		System.out.println(integer instanceof  Integer);

4.7.4 obj为class接口的实现的情况

  此处以List接口和其数组实现ArrayList为例。以个人理解,instanceof 运算符比较的是instanceof符号前面的引用的对象是否后面接口的实现,示例如下:

		ArrayList arrayList = new ArrayList();
		System.out.println(arrayList instanceof List);//true
		List list = new ArrayList();
		System.out.println(list instanceof ArrayList);//true

4.7.5 obj为class 类的直接或间接子类的情况

  该情况与上种情况比较类似,instanceof 运算符比较的是instanceof符号前面的引用的对象是否后面类或其子类,示例如下:

/*父类*/
public class Person {
     

}
/*子类*/
public class Man extends Person{
     

}
/*测试类*/
public class ClassTest {
     
	public static void main(String[] args)  {
     
		Person p1 = new Person();
		Person p2 = new Man();
		Man m1 = new Man();
		System.out.println(p1 instanceof Man);//false
		System.out.println(p2 instanceof Man);//true
		System.out.println(m1 instanceof Man);//true
	}
}

  在前面提过这样一句话“编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定”,这句话可以仍然用上面的Person类和Man类来说明,示例如下:

	System.out.println(p1 instanceof String);//编译报错
	System.out.println(p1 instanceof List);//运行时报错
	System.out.println(p1 instanceof List<?>);//运行时报错
	System.out.println(p1 instanceof List<Person>);//编译报错

4.7.6 instanceof运算符的实现

  先看Java SE 8中的实现,用伪代码表示为:

	boolean result;
	if (obj == null) {
     
	    result = false;
	} else {
     
	    try {
     
	        T temp = (T) obj; // checkcast
	        result = true;
	    } catch (ClassCastException e) {
     
	        result = false;
	    }
	}

  在执行obj instanceof T运算时,首先,会检查obj的类型是否是引用类型或空类型,如果不是则会发生编译时错误;
  其次,如果 obj 强制转换为 T 时发生编译错误,则关系表达式的 instanceof 同样会产生编译时错误;
  最后,在运行时,如果 T 的值不为null,并且 obj 可以转换为 T 而不引发ClassCastException,则instanceof运算符的结果为true。 否则结果是false。
  简单来说就是:如果 obj 不为 null 并且 (T) obj 不抛 ClassCastException 异常则该表达式值为 true ,否则值为 false

4.8 运算符优先级比较

  Java运算符优先级(从上往下依次递减):

类别 操作符 运算顺序
后缀 () [] . (点操作符) 左到右
一元 + + – (此处指的是先执行自增或自减,再执行表达式) 左到右
一元 + + – (此处指的是先执行表达式,再执行自增或自减) ! 〜 右到左
乘性 * /% 左到右
加性 + - 左到右
移位 >> >>> << 左到右
关系 > > = < < = 左到右
相等 == != 左到右
按位与、异或、或 &、^、
逻辑与、或 &&、
条件 ?: 左到右
赋值 = + = - = * = / =%= >> = << =&= ^ = =

  或者看以下的表,运算符的优先级(从高到低):
Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE_第3张图片
  如果在程序中,要改变运算顺序,可以使用()。

五、数组

  一个数组就代表在内存中开辟一段连续(意味着有序)、用来存储相同类型数据的空间,其特征如下:

  1. 数组名代表的是连续空间的首地址。
  2. 通过首地址可以依次访问数组所有元素,元素在数组中的位置叫做下标,从零开始。
  3. 数组长度一旦声明,不可改变不可追加。

5.1 声明数组

  数组的声明方式有两种,以int型数组举例:int[ ] array和int array[ ],一般用第一种方式。

5.2 创建数组

  数组的创建方式也有两种,以int型数组举例。

  • 1、int[ ] array = new int[10]
     该语句的意思是创建一个容量大小为10的int型数组,数组中默认值是0。也就是说,当数组元素未赋值时,数组元素的值为数组元素类型的默认值(此处是int型,所以默认值是0)。
  • 2、int[ ] array = {1,2,3,4,5,6} / int[ ] array = new int[ ]{1,2,3,4,5,6}
     该语句的意思是创建一个容量大小为6的int型数组,数组中的初始值为1,2,3,4,5,6。

5.3 遍历数组

  数组的遍历方式也有两种,以int型数组举例。

  1. for循环
     最常用的遍历方式,示例:
    for(int i=0;i<array.length;i++)
        System.out.println(array[i]+" ");
  1. foreach循环
     示例:
    for(int arr:array)
        System.out.println(arr+" ");

5.4 数组复制

  对数组进行复制的方法,常常有System.arraycopy和使用Arrays工具类两种方法。此处就介绍第一种,具体的方法是:

System.arraycopy(src, srcPos, dest, destPos, length)

  src: 源数组
  srcPos: 从源数组复制数据的起始位置
  dest: 目标数组
  destPos: 复制到目标数组的起始位置
  length: 复制的长度

六、工具类

6.1 Math类

  Math类包含用于执行基本数学运算的方法。常用方法有:三角函数类方法和数值计算类方法。

6.1.1 三角函数类方法

  1. public static native double acos(double d)
      double类型参数的反余弦值。
  2. public static native double asin(double d)
      double类型参数的反正弦值,范围在 -pi/2 到 pi/2 之间。
  3. public static native double atan(double d)
      double类型参数的反正切值,范围在 -pi/2 到 pi/2 之间。
  4. public static native double cos(double d)
      double类型参数的余弦值。
  5. public static native double sin(double d)
      double类型参数的三角正弦值。
  6. public static native double tan(double d)
      double类型参数的三角正切值。

6.1.2 数值计算类方法

  1. public static double abs(double d)
      double型变量的绝对值。
  2. public static double abs(double d)
      float型变量的绝对值。
  3. public static int abs(int i)
      int型变量的绝对值。
  4. public static long abs(long l)
      long型变量的绝对值。
  5. public static native double ceil(double d)
      对一个数进行上舍入,返回值大于或等于给定的参数,类型为双精度浮点型。测试代码如下:
        double d = 10.6;
        float f = -95;   
        System.out.println(Math.ceil(d));   //11.0
        System.out.println(Math.ceil(f));    //-95.0
  1. public static native double floor(double d)
      对一个数进行下舍入,返回给定参数最大的整数,该整数小于或等给定的参数。测试代码如下:
        double d = 10.6;
        float f = -95;   
        System.out.println(Math.floor(d));   //10.0
        System.out.println(Math.floor(f));   //-95.0
  1. public static native double log(double d)
      返回参数的自然数底数的对数值。测试代码如下:
    System.out.printf("log(%.3f) 为 %.3f%n", Math.E*Math.E,Math.log(Math.E*Math.E));

    结果为:

log(7.389) 为 2.000

  1. public static native double log10(double d)
      返回 double 值的底数为 10 的对数。测试代码如下:
	System.out.printf("log(%.3f) 为 %.3f%n", 100.0,Math.log10(100.0));

    结果为:

log(100.000) 为 2.000

  1. public static double max(double d1, double d2)
      返回两个 double 值中较大的一个。实现代码如下:
  2. public static float max(float f1, float f2)
      返回两个 float值中较大的一个。实现代码如下:
  3. public static int max(int i1, int i2)
      返回两个 int 值中较大的一个。实现代码如下:
  4. public static long max(long l1, long l2)
      返回两个long值中较大的一个。实现代码如下:
  5. public static double min(double d1, double d2)
      返回两个 double 值中较小的一个。实现代码如下:
  6. public static float min(float f1, float f2)
      返回两个 float值中较小的一个。实现代码如下:
  7. public static int min(int i1, int i2)
      返回两个 int 值中较小的一个。实现代码如下:
  8. public static long min(long l1, long l2)
      返回两个 long 值中较小的一个。实现代码如下:
  9. public static native double pow(double x, double y)
      返回第一个参数的第二个参数次幂的值。测试代码如下:
        double d1 = 10.0;
        double d2 = 2.0;   
        System.out.println(Math.pow(d1,d2));  //100.0
  1. public static synchronized double random()
      返回一个随机数,随机数范围为 0.0 =< Math.random < 1.0。
  2. public static long round(double d) / static int round(float f)
      “四舍五入”,算法为Math.floor(x+0.5) ,即将原来的数字加上 0.5 后再向下取整。
      测试代码:
    System.out.println(Math.round(11.5));    //12
    System.out.println(Math.round(-11.5));   //-11
  1. public static native double sqrt(double d)
      返回正确舍入的 double 值的正平方根。

6.2 Arrays类

   Arrays是一个封装好一些对数组操作的类,其中的public方法都是静态的,主要有以下几大类:

  • 1、搜索类
     该类方法的作用是在数组中搜索某个值,返回该值在数组中的下标。该类方法的实现是二分搜索,例如在int数组中搜索某个值,方法具体代码如下:
    public static int binarySearch(int[] array, int startIndex, int endIndex, int value) {
     
        checkBinarySearchBounds(startIndex, endIndex, array.length);
        int lo = startIndex;
        int hi = endIndex - 1;

        while (lo <= hi) {
     
            int mid = (lo + hi) >>> 1;
            int midVal = array[mid];

            if (midVal < value) {
     
                lo = mid + 1;
            } else if (midVal > value) {
     
                hi = mid - 1;
            } else {
     
                return mid;  // value found
            }
        }
        return ~lo;  // value not present
    }
  • 2、赋值类
     该类方法的作用是给数组中元素赋予默认值,实现是遍历赋值。示例代码如下:
    public static void fill(int[] array, int start, int end, int value) {
     
        Arrays.checkStartAndEnd(array.length, start, end);
        for (int i = start; i < end; i++) {
     
            array[i] = value;
        }
    }
  • 3、计算哈希值类
     该类方法的作用是计算数组中元素的哈希值。示例代码如下:
    public static int hashCode(int[] array) {
     
        if (array == null) {
     
            return 0;
        }
        int hashCode = 1;
        for (int element : array) {
     
            // the hash code value for integer value is integer value itself
            hashCode = 31 * hashCode + element;
        }
        return hashCode;
    }
  • 4、比较值类
     该类方法的作用是比较两个数组是否相等。
  • 5、排序类
     该类方法的作用是对数组中的元素进行排序,用到的排序方式是快速排序。示例代码如下:
    public static void sort(int[] array, int start, int end) {
     
        DualPivotQuicksort.sort(array, start, end);
    }
  • 6、转换为字符串类
     即toString方法。
  • 7、拷贝类
     该类方法的作用是拷贝数组中的元素,可以指定起始位置,未指定初始位置的话,默认从0开始。示例代码如下:
    public static int[] copyOf(int[] original, int newLength) {
     
        if (newLength < 0) {
     
            throw new NegativeArraySizeException(Integer.toString(newLength));
        }
        return copyOfRange(original, 0, newLength);
    }
  • 8、转换为List
     asList,示例:
int[] datas = {
     1,2,3,4,5,6};
List list = Arrays.asList(datas);

6.3 Collections类

  Collections类是针对集合操作的工具类。

public class Collections extends Object

  常见方法:

  1. public static void sort(List list)
    排序,默认是自然排序(排序算法是修改的归并排序算法)。使用默认排序规则和自定义规则的示例:
        Collections.sort(list);
        Collections.sort(list,new Comparator<String>() {
     
            @Override
            public int compare(String o1, String o2) {
     
                if(o1.length()>o2.length()){
     
                    return 1;
                }else if(o1.length()<o2.length()){
     
                    return -1;
                }else{
     
                    return 0;
                }
            }
        });
  1. public static int binarySearch(List list,T key)    
    二分查找(前提元素有序通过sort(List)方法)。二分查找的时候需要先进行排序操作,如果没有排序的话,是找不到指定元素的。
  2. public static T max(Collection coll)
    获取最大值
  3. public static T min(Collection coll)
    获取最小值
  4. public static void reverse(List list)
    反转(此方法以线性时间运行)
  5. public static void shuffle(List list)
    随机置换(使用默认源对指定列表进行置换)

七、分支循环

  Java中,除了普通的顺序结构外,特殊的结构有三种:

7.1 分支结构

  if、if-else、if-else if-else结构适合某个变量值在连续区间情况下的语句执行。
  switch基本语法:

switch(expression){
     
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

  switch-case结构与多种if结构作用相似,但是有局限性,其特点如下:

  1. JDK1.7之前的版本中,switch语句支持的数据类型有byte、short、int、char和枚举类型(也就是不支持long类型);在JDK1.7及以后的版本中,增加了对String类型的支持(编译后是把String转化为hash值,其实还是整数)。也就是说用于等值判断
  2. break是每种case的结束标志,如无break则会继续走下个case。
  3. 一般最后都会有个default,用来处理匹配不到任何case的情况。

  switch使用的测试代码如下:

		int grade=80;
		switch(grade){
     
			case 60:
			case 70:
				System.out.println("你的成绩为60或70分");
				break;
			case 80:
				System.out.println("你的成绩为80分");
				break;
			default:
				System.out.println("你的成绩为60、70、80之外的分数");
				break;
		}

7.2 循环结构

  Java中循环结构有两种:

  1. for循环,有三部分:初始化操作、判断终止条件表达式及迭代部分。for循环一般用于循环次数已知的情况
  2. while循环,有两种:
while(判断条件){
     
	循环体
}

do{
     
	循环体
}while(判断语句);

  do-while先执行循环体语句,然后进行判断,也就是无论如何会先执行一次循环体语句。

7.3 跳转语句

  跳转语句有三种:break、continue、return。此外,异常处理也可以改变程序执行流程。
  break有以下作用:

1>在switch中,用来终止一个语句序列。
2>用来退出一个循环。

  continue只能用来for、while、do while循环中,用于跳过当前循环,直接进行下一次循环。
  return语句使程序控制返回到调用它的地方,也就是:

1)返回方法的返回值;
2)终止当前程序。

  关于break、continue、return的使用,可以通过一段测试代码来查看其具体使用,测试代码如下:

public class SkipTest {
     
	public static void main(String[] args) {
     
		int result = sum(10);
		System.out.println("所求的数字之和是:"+result);
	}
	
	private static int sum(int num){
     
		int s = 0;
		for(int i=1;i<=num;i++){
     
			if(i==3)
				continue;
			System.out.println("i:"+i);
			s=s+i;
			if(i==(num-1))
				break;
		}
		return s;
	}
}

  这段代码的测试结果是:

i:1
i:2
i:4
i:5
i:6
i:7
i:8
i:9
所求的数字之和是:42

  这段代码是一个序列的数字之和,不过不需要+3,所以在i == 3时,使用continue,表示跳过此次循环,进入下一次循环。我们也不希望+10,所以在i == (num-1)时,使用了break,直接跳出循环。return的作用就是返回到调用该方法的地方,有返回值的话将返回值返回,无返回值的话则不用返回。

八、关键字与标识符

  Java关键字的标准定义是电脑语言里事先定义的,有特别意义的标识符,有时又叫保留字,还有特别意义的变量。Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名、方法名、类名、包名和参数

8.1 所有关键字

  java关键字共53个,包含两个保留字const,goto,具体如下:

关键字 意义
abstract 抽象
assert 断言assert是jdk1.4引入的;jvm断言默认是关闭的;断言只适用复杂的调式过程;断言一般用于程序执行结构的判断,千万不要让断言处理业务流程
boolean 布尔类型,值为true或false
break 结束一个语句块的执行,常用于switch…case和循环语句中
byte 字节类型
case 用于switch…case语句中,表示其中一个分支
catch 用于try…catch语句中,用来捕捉异常
char 字符类型
class
const 保留关键字
continue 结束本次循环,进行下一次循环,主要用于for、while循环中
default 用于switch…case语句中,表示匹配不上任何case的情况
do 用于do…while循环中,其后是要默认执行一次的语句库
double 双精度浮点类型
else 表示条件不成立的情况
enum 枚举
extends 继承,用于类和类、接口和接口之间
final 不可修改
finally 用于try…catch语句中,用来处理不论是否捕捉到异常,都执行的语句
float 单精度浮点类型
for for循环,常用于有序序列的遍历
goto 保留关键字
if 某种条件的判定
implements 实现接口,即实现接口文件中定义的空方法
import 导入其他package中的类,用于跨包间的代码调用
instanceof 判断某个对象是否属于某种类型
int 整型数据类型
interface 接口,声明一些空方法,待实现该接口的类去实现
long 长整型数据类型
native 代表调用本地C语言实现的接口
new 创建对象
package java语言中组织代码的一个单位
private 私用,代表最低的访问优先级
protected 被保护的,代表有继承等关联关系等的访问优先级
public 公共的,代表最高访问优先级
return 返回,结束方法
short 短整型数据类型
static 静态
super 表示父类
switch 多条件分支判定
synchronized 同步,代表要保证线程安全
this 表示当前类
throw 抛出某个具体异常
throws 声明在当前定义的成员方法中所有需要抛出的异常
transient 表示不需要被序列化
try 用于try…catch语句
void 表示该方法无返回值
volatile 表明两个或者多个变量必须同步地发生变化
while 用于while和do…while循环语句中

8.2 部分重要关键字

8.2.1 abstract

  abstract代表抽象,可以修饰类和方法。

  • 1、抽象方法
      abstract修饰方法时,代表抽象方法。抽象方法的特点:
       1>抽象方法没有自己的方法体;
       2>抽象方法不能用private修饰,因为抽象方法必须被子类实现(覆写),而private权限对于子类来说是不能访问的,所以就会产生矛盾;
       3>抽象方法也不能用static修饰,如果用static修饰了,就可以直接通过类名调用,而抽象方法压根就没有任何实现,这样的调用是没有意义的。
  • 2、抽象类
      abstract修饰类时,代表抽象类。抽象类的特点:
       1>抽象类不能被实例化,也就是说我们没法直接new一个抽象类,抽象类只能由它的继承类实例化;
       2>抽象类虽然不能被实例化,但有自己的构造方法;
       3>抽象类与接口(interface)有很大的不同之处,接口中不能有实例方法去实现业务逻辑,而抽象类中可以有实例方法,并实现业务逻辑,比如可以在抽象类中创建和销毁一个线程池;
       4>抽象类不能使用final关键字修饰,因为final修饰的类是无法被继承,而对于抽象类来说就是需要通过继承去实现抽象方法,这又会产生矛盾。
  • 3、抽象类和抽象方法的关系
      1>如果一个类中至少有一个抽象方法,那么这个类一定是抽象类,但反之则不然。也就是说一个抽象类中可以没有抽象方法。这样做的目的是为了此类不能被实例化。
      2>如果一个类继承了一个抽象类,那么它必须全部覆写抽象类中的抽象方法,当然也可以不全部覆写,如果不覆写全部抽象方法则这个子类也必须是抽象类。

8.2.2 final

  final代表最终的、不可更改的,可以修饰变量、方法和类。
  final修饰变量时, 如果引用为基本数据类型,则该引用为常量,该值无法修改(更准确的说法:该变量只有一次赋值的机会);如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改;如果引用时类的成员变量,则必须当场赋值,否则编译会报错。
  当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
  final修饰方法时,表示该方法无法被子类重写,但是可以被继承。
  final修饰类时,表示该类无法被继承,同时类中的所有成员方法都会被隐式定义为final方法(只有在需要确保类中的所有方法都不被重写时才使用final修饰类)。

8.2.3 static

  static关键字主要用来修饰成员变量和成员方法,在《Java编程思想》中对static关键字有如下阐述:

static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。

  简言之,使用static的目的是为了在不创建对象的前提下来调用方法/变量
  static修饰方法时,该方法称为静态方法。在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。
  static修饰变量时,称为静态变量。静态变量在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。static成员变量的初始化顺序按照定义的顺序进行初始化。
  除了修饰变量和方法外,static还可以修饰代码块,称为静态代码块。一个类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次
static是不允许用来修饰局部变量。
  静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。
  此处提一下类的初始化顺序:

  1. 父类静态变量
  2. 父类静态代码块
  3. 子类静态变量
  4. 子类静态代码块
  5. 父类普通变量
  6. 父类普通代码块
  7. 父类构造函数
  8. 子类普通变量
  9. 子类普通代码块
  10. 子类构造函数

  关于该初始化顺序,可以通过如下测试代码来验证。父类测试代码如下:

package Basic;

public class BaseClass {
     

    /*父类静态变量*/ 
    public static String baseStaticVariable = "父类-->静态变量";
    /*父类普通变量*/ 
    public String baseVariable = "父类-->普通变量";   
  
    /*静态代码块*/ 
    static{
        
        System.out.println(baseStaticVariable);   
        System.out.println("父类-->静态代码块");   
    } 
    
    /*父类构造函数*/ 
    public BaseClass() {
        
        System.out.println("父类-->构造函数"); 
    }   
    
    /*普通代码块*/ 
    {
        
        System.out.println(baseVariable);   
        System.out.println("父类-->普通代码块");   
    }   
} 

  子类测试代码如下:

package Basic;

public class SubClass extends BaseClass{
     
	
    /*子类静态变量*/ 
    public static String subStaticVariable = "子类-->静态变量";
    /*子类普通变量*/ 
    public String subVariable = "子类-->普通变量"; 
    
    public static void main(String[] args) {
     
        new SubClass();   
    }  
    
    /*静态代码块*/ 
    static {
        
        System.out.println(subStaticVariable);   
        System.out.println("子类-->静态代码块");   
    }   
    /*普通代码块*/ 
    {
        
        System.out.println(subVariable);   
        System.out.println("子类-->普通代码块");   
    }   
  
    /*子类构造函数*/ 
    public SubClass() {
        
        System.out.println("子类-->构造函数"); 
    }   
}

  测试结果如下:

父类–>静态变量
父类–>静态代码块
子类–>静态变量
子类–>静态代码块
父类–>普通变量
父类–>普通代码块
父类–>构造函数
子类–>普通变量
子类–>普通代码块
子类–>构造函数

  • static关键字特点
      1>static是一个修饰符,用于修饰成员(成员变量,成员函数)。static修饰的成员变量 称之为静态变量或类变量。
      2>static修饰的成员被所有的对象共享。
      3>static优先于对象存在,因为static的成员随着类的加载就已经存在。
      4>static修饰的成员多了一种调用方式,可以直接被类名所调用(调用方式:类名.静态成员)。
      5>static修饰的数据是共享数据,对象中的存储的是特有的数据。
  • 成员变量和静态变量的区别
      1>生命周期的不同:
       成员变量随着对象的创建而存在随着对象的回收而释放。
       静态变量随着类的加载而存在随着类的消失而消失。
      2>调用方式不同:
       成员变量只能被对象调用。
       静态变量可以被对象调用,也可以用类名调用(推荐用类名调用)。
      3>别名不同:
       成员变量也称为实例变量。
       静态变量称为类变量。
      4>数据存储位置不同:
       成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。
       静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
  • 静态使用时需要注意的事项
      1>静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
      2>静态方法中不可以使用this或者super关键字。
      3>主函数是静态的。

8.2.4 super

  super用于在子类中指代父类对象。super的三种使用情况:访问父类的方法;调用父类构造方法;访问父类中的隐藏成员变量。
  调用父类构造方法的两种情况:

  1. 直接调用super()会执行父类的无参构造方法,可以默认不写。
  2. 使用super(“父类参数”),调用父类有参构造方法,把参数传递进来就好。

  父类只有带参构造器(无参构造器没有),子类必须有相同参数的构造方法。子类必须有相同参数的构造方法,并且还需要调用super(参数)。

8.2.5 this

  super表示父类,this表示当前对象。
  this访问本类中的属性,如果本类没有此属性则从父类中继续查找。
  this访问本类中的方法,如果本类没有此方法则从父类中继续查找。
  this调用本类构造,必须放在构造方法的首行。super调用父类构造,必须放在子类构造方法首行

  • this和super的联系
  1. 在对拥有父类的子类进行初始化时,父类的构造方法也会执行,且优先于子类的构造函数执行;因为每一个子类的构造函数中的第一行都有一条默认的隐式语句super();(如果子类的构造方法中没有手动调用父类的构造方法,则会默认调用父类的无参构造方法)
  2. this() 和super()都只能写在构造函数的第一行;
  3. this() 和super() 不能存在于同一个构造函数中。第一,this()和super()都必须写在构造函数的第一行;第二,this()语句调用的是当前类的另一个构造函数而这个另一个构造函数中必然有一个父类的构造器,再使用super()又调用一次父类的构造器, 就相当于调用了两次父类的构造器,编译器不会通过;
  4. this和super不能用于static修饰的变量,方法,代码块;因为this和super都是指的是对象/实例。

8.3 标识符

  可以由自己命名的地方都称为标识符。例如,对于常量、变量、函数、语句块、类、项目等都需要一个名字,这些我们都统统称为标识符。

  • 标识符的命名规则(硬性要求)
  1. 标识符可以包含英文字母,0-9的数字,$以及_。
  2. 标识符不能以数字开头。
  3. 标识符不是关键字。
  • 标识符的命名规范(非硬性要求)
  1. 类名规范:首字符大写,后面每个单词首字母大写(大驼峰式)。
  2. 变量名规范:首字母小写,后面每个单词首字母大写(小驼峰式)。
  3. 方法名规范:同变量名。

九、传值调用和传引用调用

9.1 两者定义

  要了解传值调用和传引用调用,需要先明白形参和实参。

  • 形参和实参
      形参:用来接收调用该方法时传递的参数。只有在被调用的时候才分配内存空间(也就是仅仅在方法内有效),一旦调用结束,就释放内存空间。
      实参:传递给被调用方法的值。
  • 传值调用和传引用调用
      传值调用:传值调用中传递的参数为基本数据类型,参数视为形参。
      传引用调用:传引用调用中,如果传递的参数是引用数据类型,参数视为实参。在调用的过程中,将实参的地址传递给了形参,形参上的改变都发生在实参上。

9.2 传参举例

9.2.1 传值调用

  传值调用都是传递的基本类型,示例代码如下:

public class BasicTest1 {
     
	public static void main(String[] args) {
     
		int num = 1;
		System.out.println("形参初始值:"+num);
		print(num);
		System.out.println("形参最终值:"+num);
	}
	
	public static void print(int number){
     
		number++;
		System.out.println("形参修改值:"+number);
	}	
}

  测试结果:

形参初始值:1
形参修改值:2
形参最终值:1

  在该例子中,main方法里的num是形参,print方法体内的number是实参。
  从这个例子可以看出,虽然方法体print内的number值改变了,但是main方法内的num值仍然是原来的值。这就证明了:传值调用时,方法不会改变实参的值

9.2.2 传引用调用

  传引用调用都是传递的对象类型,示例代码如下:

public class BasicTest2 {
     
	
	private String name;
	public BasicTest2(String name){
     
		this.name = name;
	}
	public void setName(String name){
     
		this.name = name;
	}
	public String getName(){
     
		return this.name;
	}
	
	public static void main(String[] args) {
       
		BasicTest2 basicTest2 = new BasicTest2("hello");  
		test(basicTest2);  
		System.out.println(basicTest2.getName());  
	}  
	
	public static void test(BasicTest2 basicTest2){
       
		basicTest2.setName("hello world");
	}  
}

  测试结果如下:

hello world

  从这个例子可以看出:传引用调用时,可以改变对象的属性,但属性的引用是的不变的

9.3 传参总结

类别 传值调用 传引用调用
参数类型 基本类型数据 对象
是否改变原始值 改变的是形参的值,并没有改变实参的值。同时,这个传递是单向的,形参不能传递回实参 对对象做何种操作,都不会改变实参对象的引用,但是如果改变了对象的内容,就会改变实参对象的内容
接收值 方法其实接收的是参数的一个副本 方法接收的是原始值的内存地址,而不是值的副本

  同时,还有一句比较具有迷惑性的话:“在Java里面参数传递都是按值传递”。这句话可以这样理解:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递

十、BS架构和CS架构

10.1 BS、CS架构定义

  BS架构,即浏览器----服务器(Browser/Server)结构,是目前应用系统的发展方向。BS是伴随着Internet技术的兴起,对C/S架构的改进,为了区别于传统的C/S 模式,特意称为B/S模式。在这种结构下,通过W3浏览器来进入工作界面,极少部分事务逻辑在前端(Browser)实现,主要事务逻辑在服务器端(Server)实现,形成三层(3-tier)结构。
  BS的主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,难以实现传统模式下的特殊功能要求。它是瘦客户端。
  CS架构,即客户端----服务器(Client/Server)结构。C/S结构在技术上很成熟,它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。因为客户端要负责绝大多数的业务逻辑和UI展示,又称为胖客户端。
  C/S 架构是一种典型的两层架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。

10.2 BS、CS架构的优缺点

  • BS架构的优点
      1>分布性强,客户端零维护。只要有网络、浏览器,可以随时随地进行查询、浏览等业务处理。
      2>业务扩展简单方便,通过增加网页即可增加服务器功能。
      3>维护简单方便,只需要改变网页,即可实现所有用户的同步更新。
      4>开发简单,共享性强。
  • BS架构的缺点
      1>个性化特点明显降低,无法实现具有个性化的功能要求。
      2>在跨浏览器上,BS架构不尽如人意。
      3>客户端服务器端的交互是请求-响应模式,通常动态刷新页面,响应速度明显降低(Ajax可以一定程度上解决这个问题)。无法实现分页显示,给数据库访问造成较大的压力。
      4>在速度和安全性上需要花费巨大的设计成本。
      5>功能弱化,难以实现传统模式下的特殊功能要求。
  • CS架构的优点
      1>能充分发挥客户端PC的处理能力,很多工作可以在客户端处理后再提交给服务器,所以CS客户端响应速度快。
      2>操作界面漂亮、形式多样,可以充分满足客户自身的个性化要求。
      3>C/S结构的管理信息系统具有较强的事务处理能力,能实现复杂的业务流程。
      4>安全性能可以很容易保证,C/S一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。一般高度机密的信息系统采用C/S结构适宜。
  • CS架构的缺点
      1>需要专门的客户端安装程序,分布功能弱,针对点多面广且不具备网络条件的用户群体,不能够实现快速部署安装和配置。
      2>兼容性差,对于不同的开发工具,具有较大的局限性。若采用不同工具,需要重新改写程序。
      3>开发、维护成本较高,需要具有一定专业水准的技术人员才能完成,发生一次升级,则所有客户端的程序都需要改变。
      4>用户群固定。由于程序需要安装才可使用,因此不适合面向一些不可知的用户,所以适用面窄,通常用于局域网中。

十一、Java SE/Java EE/Java ME

  Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础。
  Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web 2.0 应用程序。
  Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。
  Java SE/Java EE/Java ME的区别:

  1. javase: 即J2SE, java标准版, 主要做一般的java应用, 比如, 应用软件/ QQ之类的通信软件等等。
  2. javaee: 即J2EE, 主要做企业应用, 比如公司网站, 企业解决方案等。
  3. javame: 即J2ME, 主要面向嵌入式等设备应用的开发, 比如手机游戏等。

十二、 JDK与JRE

  简单来说,JDK是Java开发运行环境,JDK包括Java程序设计语言、Jaa虚拟机、Java API类库,开发Java程序的话需要安装JDK;JREJava运行环境,如果你不需要开发只需要运行Java程序,那么你可以只安装JRE。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。

Java基础知识(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、BS/CS、Java SE/Java EE/Java ME、JDK与JRE_第4张图片

十三、 简单编程规范的判断

  1、if, for, do, while, case, switch, default 等语句自占一行,且 if, for, do, while, switch, case 等语句的执行语句无论多少都要加括号{}。 ×
  2、包的注释内容要求包括:简述本包的作用、详细描述本包的内容、产品模块名称和版本、公司版权、生成日期等。 ×
  3、类注释部分,描述部分说明该类或者接口的功能、作用、使用方法和注意事项,每次修改后增加作者、新版本号和当天的日期,@since 表示从那个版本开始就有这个类或者接口,@deprecated 表示不建议使用该类或者接口。×
  4、对于方法内部用 throw 语句抛出的异常,必须在方法的注释中标明;对于所调用的其他方法所抛出的异常,在注释中要求说明所有的异常;对于非RuntimeException,即 throws子句声明会抛出的异常,必须在方法的注释中标明。×
  5、类名和接口使用完整的英文单词描述,每个英文单词的首字母使用大写、其余字母使用小写的大小写混合法。×
  6、com.huawei.四级部门名称.项目名称,符合包命名规范。 √
  7、不能用异常来做一般流程处理的方式,不要过多地使用异常,异常的处理效率比条件分支低,而且异常的跳转流程难以预测。√
  8、划分类的时候,应该尽量把逻辑处理、数据和显示分离,实现类功能的多样化。×
  9、一个方法不应抛出太多类型的异常,如果程序中需要分类处理异常,则将异常根据分类组织成继承关系。 √
  10、switch 语句中的 case 关键字要和后面的常量保持一个空格;如果有特殊的需要要在switch 语句中定义 case 以外的标签,需要在注释中说明。 ×
  11、没有被覆盖的友好方法和没有子类的友好类应该定义成 final。√
  12、简单的类可以通过名字比较两个对象的类,推荐使用 getClass()或者 instanceof()。×
  13、不要调用 Thread 类的 resume(), suspend(),sleep(), stop() 方法。×
  14、判断方法是否是重载,只关注方法名、参数个数、参数类型,不关注方法返回值;√

你可能感兴趣的:(Java基础知识,java,1024程序员节)