JAVA学习笔记
学自 牛客网,GitHub等
基本语法
语法规范
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 FirstDemo 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
基本数据类型
内置数据类型
- byte 8字节 — 默认值是 0
- shrot 16字节 — 默认值是 0
- int 32字节 — 默认值是 0
- long 64字节 — 默认值是 0
- float 32字节 — 默认值是 0.0f
- double 64字节 — 默认值是 0.0d
- boolean boolean 数据类型表示一位的信息
只有两个取值:true 和 false
— 默认值是 false - char 16 位 Unicode 字符
引用类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
-对象、数组都是引用数据类型。 - 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
Java 常量
- 常量在程序运行时是不能被修改的。
Java 修饰符
Java语言提供了很多修饰符,主要分为以下两类:
- 访问修饰符
- 非访问修饰符
修饰符用来定义类、方法或者变量,通常放在语句的最前端。
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
-
static 修饰符,用来修饰类方法和类变量。
-
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
-
abstract 修饰符,用来创建抽象类和抽象方法。
-
synchronized 和 volatile 修饰符,主要用于线程的编程。
Java 运算符
- 算术运算符:
+, -, *, /, %, ++, --
- 关系运算符:
==, !=, >, <, >=, <=
- 位运算符:
&, |, ^, ~, <<, >>, >>>
- 逻辑运算符:
&&, ||, !
- 赋值运算符:
=, +=, -=, *=, /=, (%)=, <<=, >>=, &=, ^=, |=
- 其他运算符:
条件运算符(?:) A = B ? C : D
//instanceof 运算符``该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)
。
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真
Java 循环结构
Java中有三种主要的循环结构:
- while 循环
- do…while 循环
- for 循环
- for-each 循环
while 循环
布尔表达式为 true,循环就会一直执行下去
while( 布尔表达式 ) {
//循环内容
}
do…while 循环
对于 while 语句而言,如果不满足条件,则不能进入循环,但do…while 循环至少会执行一次。
do {
//代码语句
} while(布尔表达式)
for循环
最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。执行一次循环后,更新循环控制变量。再次检测布尔表达式。循环执行上面的过程。
for(初始化; 布尔表达式; 更新) {
//代码语句
}
for-each 循环
它能在不使用下标的情况下遍历数组
for(type element: array) {
System.out.println(element);
}
包装类型
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
Integer x = 2; // 装箱 调用了 Integer.valueOf(2)
int y = x; // 拆箱 调用了 X.intValue()
作用主要有以下两方面:
- 编码过程中只接收对象的情况,比如List中只能存入对象,不能存入基本数据类型;比如一个方法的参数是Object时,不能传入基本数据类型,但可以传入对应的包装类;
- 方便类型之间的转换,比如String和int之间的转换可以通过int的包装类Integer来实现,具体如下。
int a = new Integer(10);
啊Integer a = 10;
Java中的装箱和拆箱(缓存池技术)
简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型
基本类型的缓冲池:
- boolean values true and false
- all byte values
- short values between -128 and 127
- int values between -128 and 127
- char in the range \u0000 to \u007F
以Integer为例
Integer a=1时发生装箱过程中使用valueOf方法,Integer.valueOf()中有个静态内部类IntegerCache,里面有个常量cache[],也就是Integer常量池(其实就是缓存池技术,利用空间换时间的策略,也叫对象池),在常量池(对象池)中Integer已经默认创建了数值[-128-127]的Integer缓存数据。所以使用Integer a=1时,JVM会直接在该在对象池找到该值的引用。也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为1的对象,如果有直接返回该对象的引用;如果没有,则使用New Integer(在jvm的堆中new一个)创建一个对象,并返回该对象的引用地址。
在启动 jvm 的时候,可以通过 -XX:AutoBoxCacheMax= 修改size来指定这个缓冲池的大小。
Arrays 类
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
-
给数组赋值:通过 fill 方法。
-
对数组排序:通过 sort 方法,按升序。
-
比较数组:通过 equals 方法比较数组中元素值是否相等。
-
查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
序号 | 方法 |
---|---|
1 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型 |
2 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等) |
3 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等) |
4 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 |
命令行参数的使用
有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
命令行参数是在执行程序时候紧跟在程序名字后面的信息。
构造方法
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。
通常会使用构造方法给一个类的实例变量赋初值,或者执行其它必要的步骤来创建一个完整的对象。
不管你是否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个默认构造方法,默认构造方法的访问修改符和类的访问修改符相同(类为 public,构造函数也为 public;类改为 private,构造函数也改为 private)。
一旦你定义了自己的构造方法,默认构造方法就会失效
可变参数
尽量不要用
JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。
方法的可变参数的声明如下所示:
typeName... parameterName
在方法声明中,在指定参数类型后加一个省略号(…) 。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public int add(int... numbers){
int sum = 0;
for(int num : numbers){
sum += num;
}
return sum;
}
Java Scanner 类
下面是创建 Scanner 对象的基本语法:
Scanner s = new Scanner(System.in);
接下来我们演示一个最简单的数据输入,并通过 Scanner 类的 next() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要 使用 hasNext 与 hasNextLine 判断是否还有输入的数据:
next方法
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
// next方式接收字符串
System.out.println("next方式接收:");
// 判断是否还有输入
if (scan.hasNext()) {
String str1 = scan.next();
System.out.println("输入的数据为:" + str1);
}
scan.close();
}
}
nextline()
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 从键盘接收数据
// nextLine方式接收字符串
System.out.println("nextLine方式接收:");
// 判断是否还有输入
if (scan.hasNextLine()) {
String str2 = scan.nextLine();
System.out.println("输入的数据为:" + str2);
}
scan.close();
}
}
next() 与 nextLine() 区别
next():
- 1、一定要读取到有效字符后才可以结束输入。
- 2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
next() 不能得到带有空格的字符串。
nextLine():
- 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
- 2、可以获得空白。
Scanner类使用close()方法问题
Java通过System类进行标准的输入输出操作,当我们使用Scanner类实现键盘的数据输入,由于代码是顺序执行的,前面的一个Scanner实例假如调用了Scanner对象的close()方法,当我们再次生成一个Scanner对象实例进行输入的时候就会出现错误。
import java.util.Scanner;
public class ScannerCloseException {
public void func1(){
Scanner in = new Scanner(System.in);
in.nextLine();
in.close();
}
public void func2(){
Scanner in = new Scanner(System.in);
in.nextLine();
in.close();
}
public static void main(String[] args) {
ScannerCloseException sce = new ScannerCloseException();
sce.func1();
sce.func2();
}
- 原因
为什么呢,在func1中in调用了close()方法关闭输入流,两个方法中的in(这是两个不同的实例)使用的是同一个输入流,func1中关闭后,使用func2再次进行输入的时候,System.in已经关闭了,就不能检测输入了。
一般在main函数所在的类创建一个Scanner对象实例,在代码的最后再关闭。