引言
写这篇文章,主要是为了以后能快速复习Java的基础语法;同时,帮助有C++等语言基础的同学快速入门Java
目录
一、Java,一切皆对象
类的定义
类的实例化
子类的定义
二、包
包的创建
包的导入
系统包
三、注释
行注释
多行注释
文档注释
生成文档注释的方法
四、关键字
五、变量与常量
1.基础数据类型
2.变量的定义
编辑
3.常量的定义
六、运算符
1.算术运算符
2.比较运算符
instanceof
3.逻辑运算符
4.赋值运算符
5.位运算符
七、分支与循环
1.分支
if分支
switch分支
2.循环
for
增强型循环 for-each
while
do-while
八、字符串
1.字符串的定义
2.字符串的拼接
3.String常用方法
4.遍历字符串中的字符
九、数组
1.数组的定义
2.二维数组
3.动态数组(可变长数组)
十、集合
1.集合框架
2.栈
3.队列
4.哈希表
十一、IO
控制台输出
控制台输入
十二、Object
equals(Object obj)
hashCode()
十三、反射
Class类
十四、注解
一、Java,一切皆对象
Java是一门面向对象的语言,面向对象有三大特性:封装、继承、多态
面向对象编程(Object Oriented Programming,OOP)的一个核心问题在于把一类具有共同特征的事物抽象为类
类的定义
//定义一个类A
public class A {
//静态成员变量:
public static int num;
//实例成员变量:
public String id;
//静态方法(类方法):
public static void staticFunc(){
}
//实例方法:
public void func(){
}
//构造方法:
public A(){
this.id = "0";
}
}
类的实例化
使用 new
//类的实例化 —— 对象a
A a = new A();
//调用实例方法
a.func();
//调用类方法,类方法通过类名可以直接调用,无需实例化
A.staticFunc();
子类的定义
使用 extends
//父类A
class A {
public void doNothing(){}
}
//A的子类B
class B extends A {
}
注意
- 一个*.java源文件中可以包含多个类,比如A.java可以包含类A和类B。在上面的例子中,类A和类B访问控制级别为缺省的 default
- 但公有类(带 public
- 当一个*.java源文件包含多个类时,编译后会生成多个*.class文件,每个类对应一个class文件
对于Java而言, 一切皆对象。Java不存在全局函数和全局变量
一个最简单的Hello Worl程序,在Java中是这样的:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
二、包
随着程序的开发,我们编写的类越来越多,难免出现类重名的情况,为了解决这个问题,我们把具有类似功能的类放到一个包中。Java允许类重名,只要它们处于不同的包
包(package)是组织类的一种方式。简单理解,包就相当于文件夹,而类对应着文件,一个文件夹(包)中可以存放多个文件(类)或文件夹(包)
包的创建
包的创建使用 package 包名
在一个工程中,包名应当唯一,习惯上包名采用域名的颠倒形式
package pers.myproject.myclass;
如果项目中没有使用package创建包,系统会自动生成一个默认的包来存放编写的类
包的导入
包的导入使用 import 包名
import java.util.ArrayList;
import java.util.List;
import包的目的在于使用包中的类时,不必像下面这样输入完整的路径
java.util.List list = new java.util.ArrayList();
系统包
包 | 功能 |
java.lang | Java语言包,包含Object、String等基础类,对象,基本数据类型的包装类。自动导入,无需import |
java.util | 工具类包,含有集合类、Date类、Scanner类等 |
java.io | 主要含有与输入/输出相关的类 |
java.net | 网络编程开发包 |
java.sql | 进行数据库开发的支持包 |
java.awt | 提供创建图形用户界面相关的类 |
java.security | 提供安全方面的支持 |
三、注释
Java的注释有三种
行注释
//这是一段行注释
多行注释
/*
这是
多行注释
*/
文档注释
文档注释是指在程序中采用特定的格式进行注释,然后通过JDK提供的javadoc工具解析,生成一套网页形式的程序说明文档
/**
* @author 我
* @version 1.0
*/
public class Main {
public static void main(String[] args) {
System.out.println(add(1,2));
}
/**
* 加法
* @param a 被加数
* @param b 加数
* @return 整型
*/
public static int add(int a, int b){
return a+b;
}
}
生成文档注释的方法
1)打开*.java源文件所在目录,复制源文件所在文件夹的路径
2)[Windows+R]>输入cmd>输入 cd [*.java所在文件夹的路径]
3)输入 javadoc -d [存储文档注释的路径] -encoding UTF-8 -charset UTF-8 -author -version [*.java]
cd C:\AJava\untitled1\src
javadoc -d C:\AJava\DocComment -encoding UTF-8 -charset UTF-8 -author -version Main.java
4)找到存储文档注释的路径,双击index.html
5)文档注释的效果如下:
四、关键字
访问控制 | private、default、protect、public |
类、方法和变量修饰符 | abstract、class、new、enum、extends、final、implement、interface、native、static、strictfp、synchronized、transient、volatile |
程序控制 | for、break、continue、do、while、if、else、switch、case、instanceof、return |
异常处理 | try、catch、finally、throw、throws、assert |
基本类型 | byte、short、int、long、float、double、boolean、char |
变量引用 | super、this、void |
包相关 | import、package |
保留字 | goto、const |
注意:
1.根据官方文档的定义,看起来像关键字的null、true、false不是关键字,它们是字面量
2.访问控制的级别(√ 表示可以访问):
作用域
同一个类
同一个包
子类(可能不在同一个包)
不同包
private
√
default
√
√
protect
√
√
√
public
√
√
√
√
五、变量与常量
1.基础数据类型
Java一切皆对象,对于基础数据类型,Java也实现了它们对应的包装类
基本数据类型 | 名称 | 长度(字节) | 对应包装类 |
byte | 字节型 | 1 | Byte |
short | 短整型 | 2 | Short |
int | 整型 | 4 | Integer |
long | 长整型 | 8 | Long |
float | 单精度浮点型 | 4 | Float |
double | 双精度浮点型 | 8 | Double |
boolean | 布尔型 | 1 | Boolean |
char | 字符型 | 2 | Character |
注意:
1.Java没有无符号数
2.Java中的整数默认为int类型,浮点数默认为double类型
因此下面两种写法是非法的:
long val = 10000000000;//整数10000000000默认为int类型,不能直接赋值给long类型变量
float f = 3.14;//浮点数3.14默认为double类型,不能直接赋值给float类型变量
应当写成下面的形式:
long val1 = 10000000000L; long val2 = 10000000000l; float f1 = 3.14F; float f2= 3.14f; float f3 = (float)3.14;
2.变量的定义
Java没有全局变量,因此Java中的变量要么是类的成员(成员变量),要么在类的方法或语句块中。成员变量可以进一步分为静态成员变量和实例成员变量
静态变量需要使用 static 关键字修饰,在类加载期间都可以通过类访问其静态变量,不必创建实例就可以访问
实例变量随着对象的创建而存在,随着对象的删除而销毁,实例变量必须通过实例对象才能访问
public class Main {
int v1; //实例成员变量
static double v2; //静态成员变量
public static void main(String[] args) {
int v3 = 0; //局部变量
//变量的访问:
Main m = new Main();
System.out.println(m.v1);
System.out.println(Main.v2);//通过类名访问其静态成员变量
System.out.println(v2); //在同一个类中,可以直接访问其静态成员变量
System.out.println(v3);
}
}
3.常量的定义
Java的常量使用 final
final int NO = 123456;//习惯上我们会大写常量的标识符
和C++类似,Java的常量也具有类型,比如上例中常量NO的类型为int;和C++不同的是,C++的常量使用const修饰符定义,而Java使用final关键字
六、运算符
1.算术运算符
+ - * / % ++ -- 等
2.比较运算符
> < == != >= <= 等
instanceof
//格式:a instanceof ClassA
//判断对象a是否是类ClassA的实例,如果是则返回true
//实例代码:
public class Main {
public static void main(String[] args) {
Main m = new Main();
System.out.println(m instanceof Main);
}
}
3.逻辑运算符
&& || ! & | ^
4.赋值运算符
= += -= *= /= 等
5.位运算符
>>(右移) <<(左移) &(按位与) |(按位或) ^(异或) ~(反码)等
3 << 1 == 6 //3左移1位
3 << 2 == 12 //3左移2位
七、分支与循环
1.分支
if分支
if(布尔表达式){
...
}else if(布尔表达式){
...
}else{
}
switch分支
int type = 0;
switch (type) {
case 0:
//语句1
break;
case 1:
//语句2
break;
default:
break;
}
2.循环
for
for(int i = 0; i < 100; i++){
...
}
增强型循环 for-each
int[] arr = {1,2,3,4};
for(int vi : arr){
System.out.println(i);
}
while
//当型循环,满足条件时才执行循环体
while(布尔表达式){
循环体
}
do-while
//直到型循环,循环体至少执行一次
do{
循环体
}while(布尔表达式)
八、字符串
1.字符串的定义
String str = "hello";
2.字符串的拼接
String str1 = "hello";
String str2 = "world";
String str = str1 + str2; //str = "helloworld"
3.String常用方法
String str = "hello";
//输出字符串str的长度:
System.out.println(str.length());//输出 5
//输出str中索引为0的字符:
System.out.println(str.charAt(0));//输出 h
//输出字符'l'在字符串中第一次出现时的位置索引:
System.out.println(str.indexOf('l'));//输出 2
//比较两个字符串的内容是否相等:
String str1 = "abc";
String str2 = "abc";
if(str1.equals(str2)){
System.out.println("str1 == str2");
}
4.遍历字符串中的字符
public class Main {
public static void main(String[] args) {
String str = "hello";
for(int i = 0; i < str.length(); i++){
System.out.println(str.charAt(i));
}
}
}
九、数组
1.数组的定义
int[] arr1 = {1,2,3,4,5};
int[] arr2 = new int[]{1,2,3,4,5};
int[] arr3 = new int[5];
for(int i = 0; i < 5; i++){
arr3[i] = i + 1;
}
定义数组时,数组的长度可以由变量指定
int n = 5;
int[] arr = new int[n];
2.二维数组
int[][] arr1 = {{1,2,3},{4,5,6}};
int[][] arr2 = new int[2][3];
int no = 1;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++){
arr2[i][j] = no;
no++;
}
}
3.动态数组(可变长数组)
动态数组有多种实现方法,比较常见的是用ArrayList实现动态数组。ArrayList是List的一个实现类,它的底层是通过数组实现的
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
//创建一个动态数组:
List<Integer> arraylist = new ArrayList<Integer>();
//List arraylist = new ArrayList();
for(int i = 1; i < 6; i++){
arraylist.add(i); //在数组尾插入元素i
}
arraylist.add(6); //在数组尾插入元素6
System.out.println(arraylist.size()); //输出数组的长度
//遍历ArrayList数组方法一:
for(int i = 0; i < arraylist.size(); i++){
System.out.print(arraylist.get(i)); //get(i)获取下标为i的元素
}
System.out.println();
//删除索引(下标)为5的元素:
arraylist.remove(5);
//遍历ArrayList数组方法二:
for (Integer i : arraylist) {
System.out.print(i);
}
System.out.println();
//遍历ArrayList数组方法三:
Iterator<Integer> it = arraylist.iterator();
while (it.hasNext()){
Integer i = it.next();
System.out.print(i);
}
}
}
注意
在语句 List<Integer> arraylist = new ArrayList<Integer>();
<Integer>是泛型,List集合的元素应当是对象,而不能是基础数据类型,所以不能用
<int>而要用<Integer>。Integer是int的封装类型,在Java的自动装箱机制下,可以在需要的时候自动将int类型转化成Integer对象
十、集合
1.集合框架
Java集合框架(Java Collections Framework,JCF)是为表示和操作集合而规定的一种统一的标准的体系结构
集合的特点:集合的长度可变;集合只能存储引用类型数据,但存储的对象可以是不同数据类型
Java集合类的定义在包 java.util 下,有两个根接口 Collection 和 Map。Collection是单列集合,一次只存储一个元素;Map是双列集合,一次存储一个键值对
注意
集合存储的元素必须是对象,不能是基本数据类型,想要存储基本类型数据可以使用它们对应的包装类(Byte、Short、Integer、Long、Float、Double、Boolean、Character)
2.栈
Java中栈的实现方法有很多,这里采用Deque(双端队列)来实现栈
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
//定义一个栈:
Deque<Character> deque = new ArrayDeque<Character>();
//入栈:
deque.addLast('a');
deque.addLast('b');
deque.addLast('c');
deque.addLast('d');
//出栈:
char ch = deque.removeLast(); //removeLast()移除deque的最后一个元素并将其返回
//栈的遍历:
while (!deque.isEmpty()){
char c = deque.removeLast();
System.out.println(c);
}
}
}
输出:
3.队列
队列也可以采用Deque(双端队列)来实现
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
//定义一个队列:
Deque<Character> deque = new ArrayDeque<Character>();
//入队:
deque.addLast('a');
deque.addLast('b');
deque.addLast('c');
deque.addLast('d');
//出队:
char ch = deque.removeFirst(); //removeFirst()移除deque的最后一个元素并将其返回
//遍历整个队列:
while (!deque.isEmpty()){
char c = deque.removeFirst();
System.out.println(c);
}
}
}
输出:
4.哈希表
import java.util.*;
public class Main {
public static void main(String[] args) {
//定义一个哈希表:
Map<Character,String> map = new HashMap<Character,String>();
//添加键值对:
map.put('a',"apple");
map.put('b',"banana");
map.put('c',"coconut");
//根据键值获取value:
String strc = map.get('c');
//map.containsValue("coconut")判断map是否包含Value为"coconut"的元素
//map.map.containsKey('c')判断map是否包含Key为'c'的元素
if(map.containsValue("coconut")){
map.remove('c');//根据键值删除元素:
}
System.out.println(map.size()); //输出集合包含的元素个数
//遍历Map的方法一:
for(Character ch : map.keySet()){
//遍历keySet集合,再根据key找value
System.out.println(ch + ":" + map.get(ch));
}
System.out.println();
//遍历Map的方法二:
for (Map.Entry<Character,String> entry : map.entrySet()){
//通过entrySet()方法将map转换成Entry集合,遍历Entry集合的元素entry
System.out.println(entry.getKey() + ":" + entry.getValue());
}
System.out.println();
//遍历Map的方法三:
Iterator<Map.Entry<Character,String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
//使用迭代器遍历map
Map.Entry<Character,String> next = iterator.next();
System.out.println(next.getKey()+" : "+next.getValue());
}
}
}
十一、IO
控制台输出
- System.out.println(str); 打印完 str 后会换行
- System.out.print(str); 打印完 str 后不换行
- System.out.printf("%s", str); 格式化输出
public class Main {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = " world!";
int n = 123456;
System.out.println(str1);
System.out.println(str1 + str2 + n);
System.out.print(str1 + str2 + n);
System.out.printf("字符串:%s%s,数字:%d",str1,str2,n);
}
}
控制台输入
比较常见的方法是采用Scanner输入
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
//读取整数:
int a = scanner.nextInt();
int b = scanner.nextInt();
int c = scanner.nextInt();
//读取一个字符串(不含空格):
String s = scanner.next();
//读取一行文字:
String text = scanner.nextLine();
//输出:
System.out.println(a + " " + b + " " + c);
System.out.println(s);
System.out.println(text);
}
}
输出:
十二、Object
Object 是 java.lang 包下的一个核心类,是所有类的超类,即Object是所有类的祖先。我们定义一个类时,编译器会默认在类名之后加 extend Object
Object方法 | |
clone() | 浅拷贝,只有实现了Cloneable接口才可以调用该方法 |
getClass() | 利用反射机制,根据对象获取Class类型对象 |
toString() | 获取对象的信息,一般都会重写 |
finalize() | 释放资源,很少使用 |
equals() | 比较两个对象是否是同一个,很多类都会重写该方法 |
hashCode() | 用于哈希查找 |
wait() | 使当前线程等待该对象的锁 |
notify() | 唤醒在该对象上等待的某个线程 |
notifyAll() | 唤醒在该对象上等待的所有线程 |
equals(Object obj)
equals原本的方法是比较两个参数引用的是否是同一个对象,即直接比较两个对象的地址是否相等。很多方法重写了equals,变成了比较两个对象的内容是否相等,比如String中就重写了equals方法
/*
//类A的定义
public class A {
A(int num){
this.num = num;
}
public int num;
}
*/
public class Main {
public static void main(String[] args){
A a = new A(1);
A b = new A(1);
System.out.println(a.equals(b)); //判断a和b引用的是否是同一个对象
String str1 = "abc";
String str2 = "abc";
String str3 = "abcd";
System.out.println(str1.equals(str2)); //判断str1和str2的内容是否相等
System.out.println(str1.equals(str3)); //判断str1和str3的内容是否相等
}
}
输出:
我们可以看到,即使a、b的内容一样, equals也返回了false
hashCode()
hashCode()是用于快速查找的,如果两个对象相同 (equals返回true),那么它们的hashCode值也一定相同;如果hashCode值不同,那么这两个对象一定不相同(equals返回false)。
equals 和 hashCode 的关系
上面的说法可能有点绕,简单来说就是,程序把一个个的对象放在一些桶中,一个桶中可能包含多个对象,每个桶都有一个编号(hashCode),于是我们有以下结论:
- 当两个对象相等时( equals返回true ),它们一定在同一个桶中( hashCode返回值相等 );
- 不在同一个桶中( hashCode返回值不相等 )的两个对象一定不相等( equals返回false );
- 即使两个对象在一个桶中( hashCode返回值相等 ),它们也不一定相等( equals的值不确定 )
于是我们在比较两个对象是否相等时,可以先比较它们hashCode()的值,如果相等,再调用equals去判断;如果hashCode不相等,那么这两个对象一定不相等,就不必再调用equals了
有同学会说为什么要先用hashCode去判断,直接用equals不行吗?
对于数据量比较小的对象,直接用equals当然可以,但你设想一下这种情况:有很多个集合需要判断它们是否相等,每个集合含有的元素个数都非常多,这时候如果一一去调用equals判断就非常慢了,使用hashCode可以加速这个过程,如果两个集合它们的hashCode不相等,那就不用再调用equals去判断了
import java.util.*;
public class Main {
public static void main(String[] args){
List<Set<String>> list = new ArrayList<Set<String>>();
//初始化,创建20个相同的集合
for(int i = 0; i <20; i++){
Set<String> set = new HashSet<String>();
for(int j = 0; j <999; j++){
set.add("set" + j);
}
list.add(set);
}
//给后10个集合添加元素"abc"
for(int i = 10; i <20; i++){
list.get(i).add("abc");
}
//判断后19个集合和第一个集合是否相等
for(int i = 1; i <20; i++) {
if(list.get(0).hashCode() == list.get(i).hashCode()) {
if (list.get(0).equals(list.get(i))) {
System.out.println("set 0 == set " + i);
}
}
}
}
}
十三、反射
Java的反射机制简单来说就是,程序运行时,对任意一个类,都能找出它所有的属性和方法,以及构造它的对象;对任意一个对象,都能调用它的所有方法、获取它的所有属性
反射最常见的应用在IDEA等编译器上,当我们输入一个 类名. ,编译器会弹出该类的所有属性和方法
Class类
反射通常和Class类配套使用
假设有一个类A:
public class A {
A(int num){
this.num = num;
}
public int num;
}
a是类A的一个实例:
A a = new A(1);
我们知道a的类型是A类,那么,A的类型是什么?
在Java中,类的类型是 Class类
创建Class类型对象的方法有三种:
- Class.forName("类的完整路径(包括包路径)")
- 类名.class
- 对象.getClass()
public class Main {
public static void main(String[] args) {
//获取Class类对象的方法一:
try {
Class c1 = Class.forName("A");
System.out.println(c1);
} catch (ClassNotFoundException error) {
error.printStackTrace();
}
//获取Class类对象的方法二:
Class c2 = A.class;
//获取Class类对象的方法三:
A a = new A(1);
Class c3 = a.getClass();
System.out.println(c2);
System.out.println(c3);
}
}
十四、注解
Java的项目有两种配置方式——XML和注解
注解,也叫元数据,即描述数据的数据。简单理解的话,注解就是放在程序段前的一些标注,用来告诉编译器或JVM,这段代码的一些特点、功能或者要执行哪些特别的操作
有些注解在编译之前就被编译器过滤掉了,有些注解能保存到编译之后,还有些注解在运行期间也影响着程序
注解分为三类:标准注解、元注解、自定义注解
标准注解 | @Override | 重写方法 |
@Deprecated | 标明某个类或方法过时 | |
@SuppressWarnings | 标明要忽略的警告 | |
@SafeVarargs | 参数安全类型注解 | |
@FunctionalInterface | 函数接口注解 | |
元注解 (元注解是注解的注解) | @Retention | 标明注解被保留的阶段 |
@Documented | 标明是否生成Javadoc文档 | |
@Target | 标明注解运用的场景 | |
@Inherited | 标明注解可以被子类继承 | |
@Repeatable | 用于对同一注解多次使用 | |
自定义注解 | \ | \ |