「基础」Java语法入门

标识符是什么

关键字有哪些

Java权限修饰符

Java中有四种权限修饰符

  public protected (default) private
同一个类 yes yes yes yes
同一个包 yes yes yes no
不同包子类 yes yes no no
不同包非子类 yes no no no

注意:(default)并不是关键字"default",而是根本不写。

Java语言4种访问权限修饰符,但是仅有3个关键字,因为不写访问权限,在Java中被称为默认权限,或同包权限,本文中以(default)代替。

1、默认权限(default)

类,数据成员,构造方法,方法成员,都能够使用默认权限,即不写任何关键字。默认权限即同包权限,同包权限的元素只能在定义它们的类中,以及同包的类中被调用。

2、受保护权限(protected)

protected可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外部类,不考虑内部类)。被protected修饰的成员,能在定义它们的类中,同包的类中被调用。如果有不同包的类想调用它们,那么这个类必须是定义它们的类的子类。

3、私有权限(private)

private可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外部类,不考虑内部类)。被private修饰的成员,只能在定义它们的类中使用,在其他类中不能调用。

4、公共权限(public)

public可以修饰类,数据成员,构造方法,方法成员。被public修饰的成员,可以在任何一个类中被调用,不管同包或不同包,是权限最大的一个修饰符。

有关Java语言的修饰符,需要注意的问题有如下几个:

  • 并不是每个修饰符都可以修饰类(指外部类),只有public和default可以。
  • 所有修饰符都可以修饰数据成员,方法成员,构造方法。
  • 为了代码安全起见,修饰符不要尽量使用权限大的,而是适用即可。比如,数据成员,如果没有特殊需要,尽可能用private。
  • 修饰符修饰的是“被访问”的权限。

Java数据类型

基础数据类型

布尔型 boolean

字符型char

全球的文字放到计算机里面表示全是0和1,Unicode是统一了全世界国家文字的一种编码方式,用这样的编码可以把全世界国家的文字连接在一起。Unicode编码又分为两种,一种是Utf-8,另一种是Utf-16。JAVA所采用的是Utf-16,每一个字符占2个字节,任何国家的文字放到Unicode里面都是占2个字节。

编码表:

① ASCII码表:只能表示128个字符,单字节编码表  a-z(97-123)  \    A-Z  (65-91) \    0-9
② Unicode码表,可以表示所有的符号,固定双字节编码表
③ UTF-8码表,可以表示所有的符号,可变字节长度编码表。一个英文字母,占1个字节;一个汉字,占3个字节
④ GBK码表,可以表示中文,但不能表示世界上所有符号。一个英文字母,占1个字节,一个汉字,占2个字节

整数类型

  • 声明long型变量,必须以"l"或"L"结尾(通常为了与数字1区分,使用的是大写L);
  • 通常定义整型变量时,使用int型;
  • 整型的常量,默认类型是:int型
  • int最大值为2147483647(10位),long最大值为9223372036854775807(19位)。

浮点型

  • 浮点型,表示带小数点的数值;
  • float表示数值的范围比long还大;
  • 定义float类型变量时,变量要以"f"或"F"结尾;
  • 通常定义浮点型变量时,使用double型;
  • 浮点型的常量,默认类型为:double

浮点数在计算机底层的存储,会丢失精度,所得出的数是一个无限接近于真值的数。如果希望提高精确度,可以用BigDecimal类。

引用数据类型

引用数据类型分3种:类,接口,数组

数组:存储在一个连续的内存块中的相同数据类型(引用数据类型)的元素集合。

数组中的每一个数据称之为数组元素,数组中的元素以索引来表示其存放的位置,索引(下标)从0开始。

Java中数组必先初始化后才能使用,初始化就是给数组元素分配内存,并为每个元素赋初始值。

初始化数组的两种方式:

(1)静态初始化

语法格式:类型[] 数组名 = new 数组类型[]{元素1,元素2,元素3,...元素n};

简化语法:类型[] 数组名 = {元素1,元素2,元素3...元素n};

(2)动态初始化

如果我们事先不知道数组里存储哪些数据,只知道需要存储数据的个数,此时可以使用动态初始化方式。

动态初始化时由我们指定数组的长度,系统自动为数组元素分配初始值。

语法格式:类型[] 数组名 = new 数组类型[数组长度];

注意:无论,以哪种方式初始化数组,一旦初始化完成,数组的长度就固定了,不能改变,除非重新初始化。也就是说数组是定长的

基础类型之间的转换

自动类型转换:容量小的类型自动转换成为容量大的数据类型,数据类型按容量大小排序为:

多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行运算。

byte、short、char之间不会互相转换,它们三者在计算时首先转换成int类型

即声明为b+c的和时,m必须是int类型。

当任何基础数据类型的值和字符串值进行连接运算时(+),基础数据类型的值将自动转换为字符串类型

输出结果为hello1,任何被双引号括起来的就是字符串类型。

当需要将大容量的基础数据类型转换成小容量的数据类型时,需要进行强制转换,使用强转符(),但请注意:强制类型转换,可能导致精度丢失

强转只对就近的起作用。

byte a = (byte)3.5 * 10 + 2.5 * 20; //依旧编译出错   
更改为:byte a = (byte)(3.5 * 10 + 2.5 * 20);  //编译正确
通常,字符串类型不能直接转换成基础类型,但通过基础类型对应的包装类则可以将字符串转换成基础类型。

字符串转为基本类型需要注意的是:

① 字符串里面的值必须是可以转换成其它的基础类型的。
② String类不能转换为char。
③ 转为boolean,只要是非true的值,结果都是false。

布尔类型不可以转换成其它的基础数据类型。

基础类型包装类对象的缓存

基本类型和包装类的比较问题

Java中的基本类型及其包装类的比较(==)一直是一个比较头疼的问题,不仅有自动装箱和拆箱操作,部分的包装类还有对象缓存池,这就导致了这部分知识容易混淆。

对于==操作符来说,如果比较的数据是基本类型,则比较它们的值,如果比较的是对象,则会比较对象的内存地址。另外,如果一个是基本类型、一个是包装类型,在比较前会先把包装类型拆箱成基本类型,然后进行比较,实际上还是两个基本类型的比较。但是别忘了包装对象还有缓存池,超过缓存池的范围需要特别注意,如下:
// 自动装箱的Integer对象 和 自动装箱的Integer对象 比较,区间[-128, 127]之外
Integer i11 = 128;
Integer i12 = 128;
System.out.println("Integer autoBoxing == Integer autoBoxing,区间[-128, 127]之外,result:" + (i11 == i12));// false
System.out.println("----------------------------------------------------");

i11和i12在赋值时都会先将128自动装箱成Integer类型,然后再进行比较,比较的是内存地址。

// 自动装箱会从缓存池中取对象,缓存池的区间为[-128, 127]
// 自动装箱的Integer对象 和 自动装箱的Integer对象 比较,区间[-128, 127]中
Integer i13 = 127;// 缓存池
Integer i14 = 127;// 缓存池
System.out.println("Integer autoBoxing == Integer autoBoxing, 区间[-128, 127]中,result:" + (i13 == i14));// true

i13和i14的赋值过程中,均会触发自动装箱,给127生成对应的Integer对象;接下来使用==比较这两个Integer对象的地址,最后的输出结果为true,说明它们是同一个对象,这是因为127在Integer缓存池范围内。可以看下IntegerCache,它在Integer进行类加载的时候初始化。

Java变量

java变量分类:

Java的参数传递是「按值传递」还是「按引用传递」?

当一个对象被当作参数传递到一个方法后,在此方法内可以改变这个对象的属性,那么这里到底是「按值传递」还是「按引用传递」? 

答:是按值传递。Java 语言的参数传递只有「按值传递」当一个实例对象作为参数被传递到方法中时,参数的值就是该对象的引用的一个副本。指向同一个对象,对象的内容可以在被调用的方法内改变,但对象的引用(不是引用的副本) 是永远不会改变的。

Java 的参数传递,不管是基本数据类型还是引用类型的参数,都是按值传递,没有按引用传递!

基本数据类型的参数

public class TransferTest {
    public static void main(String[] args) {
        int num = 1;
        System.out.println("changeNum()方法调用之前:num = " + num);
        changeNum(num);
        System.out.println("changeNum()方法调用之后:num = " + num);
    }

    public static void changeNum(int x) {
        x = 2;
    }
}

运行结果:

这个传递过程的示意图如下:

num作为参数传递给changeNum()方法时,是将内存空间中num所指向的那个存储单元中存放的值1传递给了changeNum()方法中的x变量,而这个x变量也在内存空间中分配了一个存储单元,这个时候,就把num的值1传递给了x的这个存储单元中。此后,在changeNum()方法中对x的一切操作都是针对x所指向的这个存储单元,与num所指向的那个存储单元没有关系了!

所以,在changeNum()方法调用之后,num所指向的存储单元的值还是没有发生变化,这就是所谓的“按值传递”!值传递的精髓是:传递的是存储单元中的内容,而不是存储单元的引用!

直接使用双引号定义字符串方式,如:String str = "Java私塾"; 也是按值传递。

引用类型的参数

public class TransferTest2 {
    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println(p1);
        change(p1);
        System.out.println(p1);
    }

    public static void change(Person p2) {
        p2 = new Person();
    }
}

/**
 * Person类
 */
class Person {

}

运行结果:

可以看出两次打印person的地址值是一样的,即调用完change() 方法之后,person变量并没有发生改变。

这个传递过程的示意图如下:

当执行到第3行代码时,程序在堆内存中开辟了一块内存空间用来存储Person类的实例对象,同时在栈内存中开辟了一个存储单元用来存储该实例对象的引用,即上图中person指向的存储单元。

当执行到第5行代码时,person作为参数传递给change()方法,需要注意的是:person将自己存储单元的内容传递给了change()方法的p变量!此后,在change()方法中对p的一切操作都是针对p所指向的存储单元,与person所指向的那个存储单元没有关系了!

Java运算符

运算符的优先级:()优先级最高

算术运算符

+ - * / % ++ --
%运算只能在整数型时使用,浮点数不适用
++前 是变量先自加再运算,后++ 是变量先运算再自加。

赋值运算符

= 、+=、 -= 、*= 、/= 、%=

关系运算符

< > <= >= == !=
关系表达式的结果是boolean。

逻辑运算符

逻辑运算符的作用是连接多个关系表达式。& | ^ ! && ||

  • &符号:左右两端的关系表达式同时返回true的时候整个表达式返回true,有一端返回false则整个表达式是false。
  • |符号:左右两端有一端是返回true则整个表达式返回true,只有两端同时返回false整个表达式才返回false。
  • ^符号:异或就是找不同,左右两端的表达式返回的结果不一样,则返回true。左右两端返回的结果一样则返回false。
  • !:反转一个boolean表达式的结果。true变false,false变true。
  • &&:短路与,短路与左侧关系表达式为false则右侧关系表达式将不再运算。
  • ||:短路或,短路或左侧表达式返回为true则右侧表达式不再运算。

三目运算符

?:。问号左侧是一个boolean表达式。当boolean表达式的结果是true 则执行:号左侧的表达式,返回false则执行:右侧的表达式。

位运算符

& | ^ ~ << >> >>> 对于数学运算,位运算的效率更高。位运算只能操作整数

  • & 位与:两个操作数中位都为1,结果才为1,否则结果为0。
  • | 位或:两个位只要有一个为1,那么结果就是1,否则就为0。
  • ^ 位异或:两个操作数的位中,相同则结果为0,不同则结果为1。
  • ~ 位非:如果位为0,结果是1,如果位为1,结果是0。
  • << 左移 : 任何一个数左移N位,相当于这个数乘以2的N次方
  • >>右移:任何一个数右移N为,相当于这个数除以2的N次方法
  • >>> 表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
<<表示左移移,不分正负数,低位补0; 

注:以下数据类型默认为byte-8位

左移时不管正负,低位补0

正数:r = 20 << 2

  20的二进制补码:0001 0100

  向左移动两位后:0101 0000

         结果:r = 80

负数:r = -20 << 2

  -20 的二进制原码 :1001 0100

  -20 的二进制反码 :1110 1011

  -20 的二进制补码 :1110 1100

  左移两位后的补码:1011 0000

        反码:1010 1111

        原码:1101 0000 

        结果:r = -80

>>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;

注:以下数据类型默认为byte-8位

正数:r = 20 >> 2

  20的二进制补码:0001 0100

  向右移动两位后:0000 0101

       结果:r = 5

负数:r = -20 >> 2

  -20 的二进制原码 :1001 0100

  -20 的二进制反码 :1110 1011

  -20 的二进制补码 :1110 1100 

  右移两位后的补码:1111 1011 

        反码:1111 1010

        原码:1000 0101

        结果:r = -5

>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0

正数: r = 20 >>> 2

    的结果与 r = 20 >> 2 相同;

负数: r = -20 >>> 2

注:以下数据类型默认为int 32位

  -20:源码:10000000 00000000 00000000 00010100

    反码:11111111  11111111   11111111   11101011

    补码:11111111  11111111   11111111   11101100

    右移:00111111  11111111   11111111   11111011

    结果:r = 1073741819

instaceof

instanceof 是 Java 的一个二元操作符,是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。

boolean result = obj instanceof Class
  • obj 必须为引用类型,不能是基本类型,否则编译不通过。
  • System.out.println(null instanceof Object);//false
  • obj 为 Class 接口的实现类,返回true
  • obj 为 Class 类的直接或间接子类,返回true
  • 如果 obj 不为 null 并且 (T) obj 不抛 ClassCastException 异常则该表达式值为 true ,否则值为 false 。

Java流程控制

顺序结构

从上往下顺序执行的语句。

分支结构

if条件语句

switch选择结构

(1)switch支持的数据类型【切记不支持long、double、float及其包装类型】

  • 基本数据类型:char,byte, short, int
  • 包装数据类型: Character,Byte,Short,Integer
  • 枚举类型:Enum
  • 字符串类型:String(Jdk 7+ 开始支持)

(2)注意事项 

  • case 里面必须跟 break,不然程序会一个个 case 执行下去,直到最后一个 break 的 case 或者 default 出现。
  • case 条件里面只能是常量或者字面常量,而且不能为null,否则编译报错。
  • default 语句可有可无,最多只能有一个。
  • 建议在switch语句前判断参数是否为null:switch的参数不能为null,否则会报空指针异常【null的类型不确定】

循环结构

for循环语句

死循环:

for( ; ; ){

  System.out.println("循环死你呵呵");

}

while循环和do while循环

do while语句至少会执行一次

break和continue语句

部分关键字解释

final关键字

谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字。另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法。

  • 当用final修饰一个类时,表明这个类不能被继承。
  • 当用final修改一个方法时,表明该这个方法不能被子类所覆盖的。
  • 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
  • final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
  • 当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。

static关键字

原来一个类里面的成员变量,每new一个对象,这个对象就有一份自己的成员变量,因为这些成员变量都不是静态成员变量。对于static成员变量来说,这个成员变量只有一份,而且这一份是这个类所有的对象共享。

this关键字

this是一个引用,它指向自身的这个对象。

super关键字

在JAVA类中使用super来引用父类的成分,用this来引用当前对象,如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。怎么去引用里面的父类对象呢?使用super来引用,this指的是当前对象的引用,super是当前对象里面的父对象的引用。

 

posted @ 2022-01-22 14:55  残城碎梦  阅读(73)  评论(0编辑  收藏  举报