JAVA学习资料
环境配置
安装JDK
-
下载JDK
-
双击安装JDK
-
记住安装路径
-
配置环境变量
-
我的电脑==》右键==》属性==>高级系统设置
-
配置JDK环境变量==》系统变量==》点击新建==》变量名:JAVA_HOME 变量值:JDK安装路径
-
配置path变量==》系统变量==》找到path变量==》双击path变量==》点击新建:%JAVA_HOME%\bin==>点击新建:%JAVA_HOME%\jre\bin
-
测试JDK是否安装成功(命令行窗口):java -version
-
卸载JDK
-
删除JDK安装目录
-
删除JAVA_HOME
-
删除path下关于java的目录
-
测试JDK是否卸载完成(命令行窗口):java -version
注:java安装目录文件作用
bin目录:存放了java可执行程序
include目录:存放了一些引用的头文件
jre目录:存放了JAVA运行时环境
lib目录:存放了JAVA的类库文件
src.zip目录:存放了JAVA资源文件
helloWorld
第一个java程序
-
新建一个Java文件(HelloWorld.java)
-
编写代码
public class HelloWorld{ public static void main(String[] args){ System.out.print("Hello world"); } }
-
编译java文件(会生成一个HelloWorld.class字节码文件):javac HelloWorld.java
-
运行.class字节码文件:java HelloWorld
注意事项:
-
文件名和类名要保存一致。
JAVA基础语法
注释
注释并不会被执行
//单行注释 /* 多行注释 多行注释 多行注释 */ /** * 文档注释 * @param args */
标识符和关键字
Java所有的组成部分都需要名字。关键字、类名、变量名以及方法名都被称为标识符。
关键字 | 关键字 | 关键字 | 关键字 | 关键字 |
---|---|---|---|---|
abstract | assert | boolean | break | byte |
case | catch | char | class | const |
continue | default | do | double | else |
enum | extends | final | finally | float |
for | goto | if | implements | import |
instanceof | int | interface | long | native |
new | package | private | protected | public |
return | strictfp | short | static | super |
switch | synchronized | this | throw | throws |
transient | try | void | volatile | while |
注意事项:
-
所有标识符都应该以字母(A~Z或者a~z)、美元符($)、或者下划线(_)开始。
-
首字母之后可以是(A~Z或者a~z)、美元符($)、下划线(_)或者数字的任意字符组合。
-
不能使用关键字作为变量名或方法名。
-
标识符是大小写敏感的。
-
标识符可以使用中文命名,但是不建议这样使用。
数据类型
基本类型:
byte、short、int、long、float、double、char、boolean
引用类型:
String、类、接口、数组
//整数拓展 public static void demo(){ int i = 10; //十进制 int i2 = 010; //八进制 int i3 = 0x10; //十六进制 System.out.println(i+"~"+i2+"~"+i3); }
//浮点数拓展 //float 有限、离散、舍入误差、大约、接近但不等于 public static void demo(){ float f = 0.1f; //0.1 double d = 1.0/10; //0.1 System.out.println(f==d); //false float f1 = 231313123123f; float f2 = f1 + 1; System.out.println(f1 == f2);//true }
//字符拓展 //所有的字符本质还是数字 //编码 Unicode 2字节 0~65536 // Excel 2^16 65536 public static void demo(){ char c1 = 'a'; char c2 = '中'; System.out.println(c1+"~"+(int)c1); System.out.println(c2+"~"+(int)c2); }
//转义字符 //\t 制表符 //\n 换行符 //字符串拓展 public static void demo(){ String s1 = new String("hello world"); String s2 = new String("hello world"); String s3 = "hello world"; String s4 = "hello world"; System.out.println(s1 == s2); //false System.out.println(s3 == s4); //true }
类型转换
强制类型转换:(类型)变量 高==》低
自动类型转换: 低==》高
注意事项:
-
不能对boolean值进行转换
-
不能把对象类型转换为不相干的类型
-
在把高容量转换到低容量的时候,强制转换
-
转换的时候可能存在内存溢出,或者精度问题
变量、常量、作用域
java是一种强类型语言,每个变量都必须声明其类型;java的变量是最基本的存储单元。
变量格式:数据类型 变量名 = 变量值;
变量类型 | 变量作用域 |
---|---|
类变量 | 作用于类中,用static修饰 |
实例变量 | 作用于类中,无static修饰 |
局部变量 | 作用于方法中 |
注意事项:
-
所有变量名、方法名、类名:见名知意
-
类变量、局部变量、方法名命名规则:首字母小写和驼峰命名(sepllName)
-
常量命名规则:大写字母+下划线(SPELL_NAME)
-
类名命名规则:首字母大写和驼峰命名(SepllName)
运算符
运算符类型 | 示例 |
---|---|
算术运算符 | +、-、*、/、%、++、-- |
赋值运算符 | = |
关系运算符 | >、<、>=、<=、==、!=、instanceof |
逻辑运算符 | &&、||、! |
位运算符 | &、|、^、~、>>、<<、>>> |
条件运算符 | (表达式)?(表达式为true时返回) :(表达式为false时返回) |
拓展运算符 | +=、-+、*=、/= |
JavaDoc生成文档
命令格式(命令行执行):javadoc -encoding UTF-8 -charset UTF-8 XXX.java
JAVA流程控制
顺序结构
Java的基本结构就是顺序结构,除非特别指明,否则就按顺序一句一句执行。
选择结构
if单选择结构
if(boolean表达式){ //如果boolean表达式为true将执行的语句 }
if双选择结构
if(boolean表达式){ //如果boolean表达式为true将执行的语句 }else{ //如果boolean表达式为false将执行的语句 }
if多选择结构
if(boolean表达式1){ //如果boolean表达式1为true将执行的语句 }else if(boolean表达式2){ //如果boolean表达式2为true将执行的语句 }else if(boolean表达式3){ //如果boolean表达式为3true将执行的语句 }else{ //如果boolean表达式为false将执行的语句 }
switch多选择结构
/* *switch语句中的变量类型可以是: *byte、short、int、char *从JAVA SE 7开始,switch支持String类型的字符串 *case标签必须为字符串常量或字面量 */ switch(expression){ case value1: //语句 break;//可选 case value2: //语句 break;//可选 //可以有任意数量的case语句 default://可选 //语句 }
循环结构
while循环
while(boolean表达式){ //循环内容 }
do...while循环
//特点:至少执行一次循环内容 do{ //循环内容 }while(boolean表达式);
for循环
for(初始化; boolean表达式; 更新){ //循环内容 } //示例(打印1~100): for (int i = 0; i <= 100; i++) { System.out.println(i); }
增强for循环
//主要用于遍历数组和集合对象 for(声明语句 : 表达式){ //循环内容 } //示例 int[] numbers = {10,20,30,40,50};//定义一个数组 for (int number : numbers) { System.out.println(number); }
break、continue、goto
关键字 | 释义 |
---|---|
break | break用于强制退出循环,不执行循环中剩余的语句。 |
continue | continue用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。 |
goto(保留字) | 由于break和continue关键字通常只中断当前循环,但若是随着标签使用,他们就会中断到存在标签的地方。 |
//goto用法示例(打印100~150之间的质数): int count = 0; outer: for (int i = 100; i < 150; i++) { for (int j = 2; j < i/2; j++) { if(i%j == 0){ continue outer; } } System.out.print(i+" "); }
Java中的方法
方法的定义和调用
方法包含一个方法头和一个方法体,以下是一个方法的所有组成部分:
-
修饰符:定义了该方法的访问类型。
-
返回值类型:调用方法,回得到一个与返回值相对应的结果。
-
方法名:方法的实际名称,方法名和参数列表共同构成方法签名。
-
参数类型:参数像是一个占位符,当方法被调用时,传递值给参数,这个值被称为实参,而参数被被称为形参;参数列表指的是参数的类型、顺序和数量。
-
方法体:方法体包含具体的语句,定义了该方法的功能。
修饰符 返回值类型 方法名(参数类型 参数名, 参数类型 参数名...){ ...... 方法体 ...... return 返回值 } //示例 public static String method1(int age, String name){ //方法体 return "返回值"; }
方法的重载
重载指的是在同一个类中,具有相同的方法名,但是参数列表不同的方法。
方法重载的规则:
-
方法名必须相同
-
参数列表必须不同(参数类型、参数个数、参数顺序)
-
方法的返回值可以相同也可以不相同
-
仅仅返回值类型不相同不足以构成方法的重载
//示例 public String method1(int age, String name){ //方法体 return "返回值"; } public String method1(){ //方法体 return "返回值"; }
可变参数
在方法声明中,在指定参数类型后面加一个省略号(...)
一个方法只能指定一个可变参数,并且这个可变参数必须是方法的最后一个参数
//示例 public String method1(int age, String... names){ //方法体 return "返回值"; }
递归
递归就是自己调用自己。递归包含两部分:
-
递归头:什么时候不调用自身方法,如果没有头将陷入死循环。
-
递归体:什么时候需要调用自身方法。
//示例(阶乘的计算) public static int calFactorial(int num){ if(num<=1){ return 1; }else{ return num*calFactorial(num-1); } }
Java中的数组
数组的定义
-
数组是相同类型数据的有序集合
-
数组中的每一个数据称作一个数组元素,每个数组元素可以通过下标来访问他们。
数组的声明和创建
-
数组是通过索引访问的,数组索引从0开始。
-
获取数组的长度:arrays.length
//数组的声明 //方式一 dataType[] arrayRefVar; //方式二 dataType arrayRefVar[]; //数组的创建 //方式一 dataType[] arrayRefVar = new dataType[arraySize]; //方式二 dataType[] arrayRefVar = {arrayValue1, arrayValue2, arrayValue3...}; //示例 //方式一 int[] nums = new int[4]; num[0] = 1; num[1] = 2; num[2] = 3; num[3] = 4; //方式二 int[] nums = {1,2,3,4};
数组的基本特点
-
其长度是确定的。数值一旦被创建,它的大小就不可以改变。
-
其元素类型必须是相同类型,不允许出现混合类型。
-
数组中的元素可以是任何数据类型,包括基本类型和引用类型。
-
数据变量属于引用类型。数组也可以看出是对象,数组中的每个元素相当于该对象的成员变量。
多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每个元素都是一个一维数组。
//二维数组(以下数组可以看作是一个两行五列的数组) int nums[][] = new int[2][5]; //三维数组 int nums[][][] = new int[2][5][7];
Java内存:
-
堆:存放new的对象和数组;可以被所有线程共享,不会存放别的对象引用。
-
栈:存放基本变量类型(会包含这个基本变量的具体数值);存放引用对象的变量(会存放这个引用在堆里面的具体地址)
-
方法区:存放了所有的class和static变量;可以被所有线程共享。
异常:
-
数组下标越界异常:ArrayIndexOutOfBoundsException
稀疏数组
//稀疏数组(记录有效的坐标:记录原始坐标及有效值) public void sparseArray(){ //创建一个二维数组(模拟五子棋) 11*11 0:没有棋子 1:黑棋 2:白棋 int[][] array1 = new int[11][11]; array1[1][2] = 1; array1[2][3] = 2; array1[1][3] = 1; array1[1][4] = 2; //输出原始数组 System.out.println("===================原始数组======================="); for (int[] ints : array1) { for (int anInt : ints) { System.out.print(anInt + "\t"); } System.out.println(); } System.out.println("===================稀疏数组======================="); //将二维数组转换为稀疏数组保存 //1.获取有效值的个数 int sum = 0; for (int i = 0; i < 11; i++) { for (int j = 0; j < 11; j++) { if(array1[i][j] != 0){ sum++; } } } System.out.println("有效值的个数:"+sum); //2.创建一个稀疏数组(行-列-值) int[][] array2= new int[sum+1][3]; array2[0][0] = 11;//总行数 array2[0][1] = 11;//总列数 array2[0][2] = sum;//有效值总个数 //遍历二维数组,将非0的值放入稀疏数组中 int count = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1[i].length; j++) { if(array1[i][j] != 0){ count++; array2[count][0] = i;//行 array2[count][1] = j;//列 array2[count][2] = array1[i][j];//值 } } } //输出稀疏数组 for (int i = 0; i < array2.length; i++) { System.out.println(array2[i][0] +"\t"+array2[i][1] +"\t"+array2[i][2]); } System.out.println("===================还原数组======================="); //1.还原数组 int[][] array3 = new int[array2[0][0]][array2[0][1]]; //2.读取稀疏数组,将其中的元素还原他的值(第0行为行头数据,非有效数据) for (int i = 1; i < array2.length; i++) { array3[array2[i][0]][array2[i][1]] = array2[i][2]; } //输出还原的数组 for (int[] ints : array3) { for (int anInt : ints) { System.out.print(anInt + "\t"); } System.out.println(); } } ===========================执行输出==================================== ===================原始数组======================= 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ===================稀疏数组======================= 有效值的个数:4 11 11 4 1 2 1 1 3 1 1 4 2 2 3 2 ===================还原数组======================= 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
八大排序
冒泡排序
//冒泡排序 /* 1.比较数组中,两个相邻的元素,如果第一个数比第二个数大,则交换他们的位置 2.每一次比较,都会产生一个最大,或者最小的数字 3。下一轮则可以少一次排序 4.依次循环,直到结束 */ public void bubbleSort(){ //定义一个数组 int[] array = {9,23,5,43,64,4,66,44,77,19}; //临时变量,用于两个数之间交换位置 int temp = 0; //外层循环,判断我们要走多少次 for (int i = 0; i < array.length-1; i++) { //通过flag标识减少没有意义的排序 boolean flag = false; //内层循环,判断两个数,如果第一个数比第二个数大,则交换他们的位置 for (int j = 0; j < array.length-1-i; j++) { if(array[j+1] > array[j]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; flag = true; } } if(!flag){ break; } } //输出排序结果 for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } } ===========================执行输出==================================== 77 66 64 44 43 23 19 9 5 4
面向对象
面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封存)数据。
面向对象的三大特性:封装、继承、多态。
类和对象的创建
//主程序 public class Application { public static void main(String[] args) { //类:抽象的,实例化 //类实例化后会返回一个自己的对象 //smith、jamms就是student类的具体实例 //实例化一个对象 Student smith = new Student(); smith.name = "史密斯"; smith.age = 18; System.out.println(smith.name+"~"+smith.age); //实例化一个对象 Student jamms = new Student(); jamms.name = "詹姆斯"; jamms.age = 21; System.out.println(jamms.name+"~"+jamms.age); } } //学生类 public class Student { //属性:字段 String name; int age; //方法 public void study(){ System.out.println(this.name + "在学习"); } } ===========================执行输出==================================== 史密斯~18 詹姆斯~21
内存分析:
-
栈:smith、jamms:引用变量名
-
堆:new Student()、study()
构造器
使用new关键字创建的时候,除了分配内存空间外,还会给创建好的对象,进行默认的初始化及堆类中构造器的调用。
构造器有以下两个特点:
-
必须和类名字相同
-
没有返回类型,也不能写void
/* 构造器: 1.和类名相同 2.没有返回值 作用: 1.new 本质是在调用构造方法 2.初始化对象的值 注意点: 1.定义有参构造后,如果想使用无参构造,需要显示定义一个无参构造 构造器快捷键: Alt+Insert */ //主方法 public class Application { public static void main(String[] args) { Person person1 = new Person(); Person person2 = new Person("Bug"); System.out.println(person1.name+"~"+person2.name); } } //类 public class Person { //一个类即使什么都不写,它也会存在一个构造方法 //使用new关键字,本质是在调用构造器 //构造器一般用来初始化值 String name; //显示定义构造器 // 无参构造(默认) public Person(){ this.name = "Aug"; } //有参构造(一旦定义了有参构造,无参构造就必须显示定义) public Person(String name){ this.name = name; } } ===========================执行输出==================================== Aug~Bug
封装
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏(get/set)。程序设计要追求 "高内聚,低耦合"。高内聚就是内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量方法给外部使用。
public class Person { /* 封装的意义(get/set): 1.提高代码的安全性,保护数据 2。隐藏代码的实现细节 3.统一接口 4.增加系统可以维护性 */ private String name; public String getName(){ return this.name; } public void setName(String name) { this.name = name; } }
继承
继承的本质是对某一批类的抽象。Java中只有单继承,继承关系的两个类,一个为子类(派生类),一个为父类(基类),使用关键字extends来表示。子类和父类之间,从意义上讲应具有 "is a" 的关系。
//主方法 public class Application { public static void main(String[] args) { Student student = new Student(); student.say(); } } //在Java中,所有的类都默认直接或间接继承Object //父类 public class Person { //修饰符:public、protected、default、private public String name; private int age; public void say(){ System.out.println("Hello World !!!"); } } //子类继承了父类,就会拥有父类的非private的全部属性和方法 //子类 public class Student extends Person { } ===========================执行输出==================================== Hello World !!!
super和this
//主方法 public class Application { public static void main(String[] args) { /* super注意点: 1.super调用父类的构造方法,必须在构造方法的第一个 2.super只能出现在子类方法或者构造方法中 3.super和this不能同时调用构造方法 this和super的差异: 1.代表对象不同 this:代表本身调用者这个对象 super:代表父类对象 2.前提条件 this:没有继承关系也可以使用 super:只能在继承条件下使用 3.构造方法 this(); 本类的构造 super(); 父类的构造 */ Student student = new Student(); student.test("Stranger"); } } //父类 public class Person { public Person() { System.out.println("Person无参执行了"); } protected String name = "Father"; } //子类 public class Student extends Person { public Student() { //隐藏代码super(); 调用了父类的无参构造。 // 调用父类的构造器,代码必须在子类的第一行 super(); System.out.println("Student无参执行了"); } private String name = "Son"; public void test(String name){ System.out.println(name); System.out.println(this.name); System.out.println(super.name); } } ===========================执行输出==================================== Person无参执行了 Student无参执行了 Stranger Son Father
重写
//主方法 public class Application { public static void main(String[] args) { /* 重写(子类和父类方法必须一致,仅方法体不同): [需要有继承关系,子类重写父类的方法,只跟非static方法有关] 1.方法名必须相同 2.参数列表必须相同 3.修饰符范围可以扩大,但不能缩小:public > protected > default > private 4.抛出的异常范围可以缩小,但不能扩大 */ Student student = new Student(); Person person = new Student(); student.test(); person.test(); } } //父类 public class Person { public void test(){ System.out.println("Person=>test"); } } //子类 public class Student extends Person { @Override public void test() { System.out.println("Student=>test"); } } ===========================执行输出==================================== Student=>test Student=>test
多态
多态是同一方法可以根据发送对象的不同,而采用多种不同行为的方式。
一个对象的实际类型是确定的,但可以指向对象引用的类型有很多。
多态存在的条件:有继承关系;子类重写父类的方法;父类引用指向子类对象
//主方法 public class Application { public static void main(String[] args) { /* 多态注意事项: 1.多态是方法的多态,属性没有多态 2.父类和子类,有联系,类型转换异常! ClassCastException! 3.存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son(); 4.不能被重写的方法 a.static方法,属于类,不属于实例 b。被fianl修饰的方法,常量 c。被private修饰的方法,私有 */ //一个对象的实际类型是确定的 //new Student(); //new Person(); //可以指向的引用类型就不确定了:父类的引用指向子类 Student student = new Student(); Person person = new Student(); Object object = new Student(); //student 能调用的方法都是自己的或者继承父类的 student.run(); //person 父类型,可以指向子类,但不能调用子类的独有方法 //person.run(); //对象能执行哪些方法,主要看对象左边的类型,和右边关系不大 ((Student) object).run();//子类重写了父类的方法,执行子类的方法 } } //父类 public class Person { public void test(){ System.out.println("Person=>test"); } } //子类 public class Student extends Person { @Override public void test() { System.out.println("Student=>test"); } public void run(){ System.out.println("run"); } } ===========================执行输出==================================== run run
X instanceof Y:X、Y存在父子关系,结果为True
static
//主方法 public class Application { public static void main(String[] args) { Person person1 = new Person(); System.out.println("========================="); Person person2 = new Person(); System.out.println("========================="); person1.test(); } } //静态导入包 import static java.lang.Math.random; //父类 public class Person { //执行顺序:静态代码块 > 匿名代码块 > 构造方法 // public Person(){ System.out.println("构造方法"); } // { System.out.println("匿名代码块"); } //只执行一次 static{ System.out.println("静态代码块"); } public void test(){ System.out.println(random()); } } ===========================执行输出==================================== 静态代码块 匿名代码块 构造方法 ========================= 匿名代码块 构造方法 ========================= 0.2024487810796991
抽象类
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
子类继承抽象类,那么就必须哟啊实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
//abstract 抽象类 public abstract class Action { /* 抽象类 1.不能new这个抽象类,只能靠子类去继承它:约束 2.抽象方法必须写在抽象类中 3.抽象类中可以写普通方法 */ //抽象方法,只有方法名字,没有方法的实现 public abstract void doSomething(); public void study(){}; }
接口
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范!!!(约束和实现分离)
//interface 定义的关键字,接口都需要有实现类 public interface UserService { //接口中的所有定义都是抽象的,默认修饰符为public abstract /* 接口的作用 1.约束 2.定义一些方法,让不同的类实现 3.接口不能被实例化,接口中没有构造方法 4.implements可以实现多个接口 5.实现了接口的类,就需要重写接口中的方法 */ public abstract void insert(String name); public abstract void delete(String name); public abstract void update(String name); public abstract void selete(String name); } public interface TimeService { void timer(); } //接口实现类:实现了接口的类,就需要重写接口中的方法 public class UserServiceImpl implements UserService,TimeService { @Override public void insert(String name) { } @Override public void delete(String name) { } @Override public void update(String name) { } @Override public void selete(String name) { } @Override public void timer() { } }
内部类
成员内部类
//主方法 public class Application { public static void main(String[] args) { Outer outer = new Outer(); //通过外部类来实例化成员内部类 Outer.Inner inner = outer.new Inner(); inner.in(); inner.getId(); inner.getOut(); } } //外部类 public class Outer { private int id = 10; private void out(){ System.out.println("这是外部类的方法"); }; //成员内部类 public class Inner{ public void in(){ System.out.println("这是成员内部类的方法"); } //内部类可以访问外部类的私有属性和方法 public void getId(){ System.out.println(id); } public void getOut(){ out(); } } } ===========================执行输出==================================== 这是成员内部类的方法 10 这是外部类的方法
静态内部类
//静态内部类无法访问非静态的属性和方法 public static class Inner{ public void in(){ System.out.println("这是静态内部类的方法"); } }
局部内部类
匿名内部类