该系列学习笔记仅作学习过程中的知识点整理,先整体、再细节,需要扩展的部分暂作标注,后续会逐渐填坑,
Day 01
1. Java起源
由Sun公司推出,James Gosling领导开发,前身是Oak语言,95年推出由Oak语言开发能将小程序嵌入网页执行的技术-Applet,同年正式更名为Java
推出多个版本:JavaSE、JavaEE、JavaME
JavaSE: 主要应用于桌面开发和低端商务开发
JavaEE: 以企业为环境而开发应用程序的解决方案, 服务器方向的开发
JavaME: 主要用于嵌入式设备开发
目前最新的长期支持版本LTS: JavaSE 11, 所以后续的学习使用该版本Java
2. Java体系特点
1 面向对象=>面向对象 后面补
2 跨平台,可以在不同的平台下使用, linux,windows…
3 基于c/c++ 语言robust
4 安全性得益于 强类型机制、异常处理、垃圾回收
3. Java跨平台原理 (细节待补)
Step1 Java源代码通过编译器编译成字节码 =>一个class文件
Step2 字节码传输到运行平台上
Step3 类装载器将字节码进行验证,同时引入Java类库结合起来传入JVM
Step4 进入JVM中首先通过Java解释器翻译和即时编译器成指令,然后通过运行期系统将指令发给操作系统
Step5 操作系统将指令发给硬件
4. JVM概念(JVM待补)
有一个解释器组件实现Java字节码和操作系统的通信
不同的运行平台有不同的JVM
5. GC(Garbage Collection)
Java自动回收垃圾,JVM提供系统线程用于跟踪储存空间的分配情况,检查并释放可被释放的空间
6. JDK JRE
JDK 开发工具集
JRE 运行程序的工具,JDK包括JRE
7. 环境变量
为命令执行提供外部命令目录配置
内部命令:文件夹中提供的命令
外部命令:环境提供的命令
windows中高级系统设置PATH
8. JAVA_HOME
windows上切换版本只用改JAVA_HOME就行
查看:cd /Library/Java/JavaVirtualMachines/ =>ls
mac设置JAVA_HOME:
Step1: to know the location of JAVA_HOME: /usr/libexec/java_home -v11
可以看到 /Library/Java/JavaVirtualMachines/jdk-11.0.8.jdk/Contents/Home
Step2: vim ~/.bash_profile => i => 加上 export JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk-11.0.8.jdk/Contents/Home => esc => :wq
Step3: source ~/.bash_profile
Step4: echo $JAVA_HOME 可以看到配置好了 或者java -version 或者javac -version
windows设置JAVA_HOME可以解决系统同时存在多版本Java的问题, 如果有多个版本的java mac应该如何设置(已解决): mac中多版本Java.
9. 代码分类
结构定义语句:大括号
功能执行语句:定义在方法内;功能执行语句必须以分号结束
Day 02
1. 二进制
Bit:表示一个二进制数码0或者1,是计算机储存处理信息的最基本的单位
Byte: 一个字节由8个bit组成,表示作为一个完整处理单元的8个二进制数码,包含八位的二进制数;是用于计量存储容量的一个计量单位,作为一个单位来处理的一个二进制数字串是构成信息的一个小单位。
Byte 11111111=>0-255
2. 变量
按照数据类型分类:
基本数据类型(8类)
数值型:整数:byte,short(2B),int(4B),long(8B)
浮点:float(4B),double(8B)
布尔型 boolean
引用数据类型(3类): class, interface,数组
按照声明的位置划分:
局部变量:方法或者语句内部
成员变量:方法外部、类的内部
3. 标识符
Java对包、类、方法、参数、变量等要素命名时使用的字符序列
1 由字母数字下划线$组成
2 不能以数字开头
3 区分大小写
4 长度无限制,必须见名知意
5 不能是Java中的保留关键字
创建变量:数据类型 变量名 = 初始化值;数据类型 变量名
双引号:string 单引号:char
eclipse mac快捷键 =》Syso=> control+space
4. 数据类型转换
自动转换
Boolean 类型不能转换为其他任何数据类型
容量小的可以转换为容量大的
Byte,short,int->float->long->double
Byte short int不会相互转换它们三个在计算的时候会转换成int类
强制转换
容量大的转为容量小的
long l = 100L; int i = (int) l;
两个坑
1 double 和float类型的变量定义
如:float f1 = 10.1;会报错 因为手动输入的小数默认类型是double ,所以通常使用float f1 = 10.1f;
2 long类型变量定义
如:long l = 20000000000; 会报错,因为默认手动输入的整数是int,如果超出了int的取值范围就会报错
于是解决 long l = 20000000000l;
char类型
使用单引号引入 中间放一个字符 可加减 成为另一个char 因为中间通过ascii 转换
5. 方法
用于封装逻辑
权限修饰符 返回值声明 方法名称(参数列表){
方法中封装的逻辑功能;
return 返回值;
}
6. 运算符
1 算术运算符 ++i i++ 的区别++i先加1再参与运算 i++先参与运算再加1
2 赋值
3 关系运算符
4 逻辑 & | && || 其中&& 是短路与 ||是短路或 结果和& |是一样的,不过 && 会提前终止进程 如果&&前面是false ||会提前终止进程如果||前面是true
5 字符串连接
与python不同的地方: java 字符串+数字=》字符串 而python会报错
6 三目运算符
X?Y:Z X是布尔结果表达式 如果为True 则执行Y 如果为False则执行Z
7. 变量作用域
会报错 因为a b属于两个范围
8. 编程规范(阿里)
1 命名:代码中命名不能以下划线或者美元符号开始 也不能以其结束
2 代码中命名不可拼音与英文混合
3 类名使用UpperCamelCase 多个单词组成每一单词首字母都大写
4方法名、参数名、成员变量名、局部变量名统一使用lowerCamelCase 多个单词组成第一个单词开头小写剩下的单词首字母大写
5 常量命名全部大写,单词间下划线隔开
9. 转义字符
Day 03
1 接收用户的键盘输入
1 定义一个Scanner类
2 System.in 扫描输入
3 input.nextLine() input.next() 默认是string类型 不能同时使用
next只能接收一段 回车和空格都能使其停止;next必须有东西输入,即输入有效的字符才能结束只输入一个空格不行
nextLine只能通过回车停止 中间可以输入空格
package day01;
import java.util.Scanner;
public class Demo3 {
public static void main(String[] args) {
// System.in 扫描系统的输入
Scanner input = new Scanner(System.in);
System.out.println("请输入一段数字:");
// 用于接收各种数据类型 但是next 和nextLine不能同时使用
String s = input.next();
String s2 = input.nextLine();
int i = input.nextInt();
System.out.println(i);
}
}
2. 执行结构
顺序结构
分支结构:
if if… else… if… else if … if… else if … else…
对比: python中 就是if elif else ; java 是 if else if else
switch结构
switch(表达式){
case 取值1:语句块;break;
case 取值2:语句块;break;
case 取值3:语句块;break;
default: 语句块;break;
}
表达式的返回值必须是int short char byte string
case子句的取值必须是常量,且所有case子句的取值应该是不同的
default子句是可选的 如果无则直接跳出结构
如果没有break则会继续向下执行
循环结构
while循环:先判断再执行
for (定义循环变量;判断循环条件;循环变量更新)
3. break与continue
4. 退出多重循环
break 只能退出一重循环
多重循环可以命名
5. 判断输入类型
if (input.hasNextInt()) {
int num = input.nextInt();
System.out.println(num);
}else {
}
Day 04
1. 数组
数组中的数据必须得是相同数据类型
python中的list不需要
2. 数组格式
常用格式:
1)数据类型[] 数组名称 = new 数组类型[数组长度]
2)数据类型[] 数组名称 = {数组内容1,数组内容2,数组内容3… 数组内容n}
注意是大括号
int[] ages = {1,2,3,4,5};
int[] ages = new int[10];
不常用的格式
数据类型[] 数组名称 = new 数组类型[]{数组内容1,数组内容2,数组内容3… 数组内容n}
数据类型[] 数组名称
3. 数组格式
数组赋值
数组长度 数组名称.length
4. 数组常见问题
1)数组下标越界
2)空指针问题:一个数组需要占用一段内存,但是名称与值之间并未绑定在一起或者没有值,则出现名称指向的值不存在,即为空指针问题
int[]nums = null;
5. 排序
冒泡排序
补充:
冒泡排序分析:空间复杂度O(1)
时间复杂度:
最好情况下有序时间复杂度O(N)
最坏的情况下O(N^2)
当最坏的情况下(逆序)比较次数为n(n-1)/2 移动次数为3n(n-1)/2
冒泡排序是稳定排序
package day01;
public class BubbleSort {
public static void main(String[] args) {
int[] nums = {5,3,1,2,3,4};
for(int i= 0; i<nums.length-1;i++) {
for(int j=0;j<nums.length-i-1;j++) {
if (nums[j]>nums[j+1]) {
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
for(int i=0;i<nums.length;i++) {
System.out.println(nums[i]);
}
}
快速排序
package day01;
import java.util.Arrays;
public class Assignment3 {
public static void main(String[] args) {
int[] arr = {1,3,9,5,6,7,15,4,8};
quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr, int l, int r) {
if(l >= r) {
return;
}
int x = (arr[l]+arr[r])/2;
int i = l-1;
int j = r+1;
int temp;
while(i<j) {
do i++; while(arr[i]<x);
do j--; while(arr[j]>x);
if(i<j) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
quickSort(arr,l,j);
quickSort(arr,j+1,r);
}
}
6. 二分查找
习惯使用的模板Java版
package day01;
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {10,20,30,40,40,50,60,70,80};
int l = 0;
int r = arr.length-1;
int mid = 0;
int target = 40;
// 方法一
// 返回的是从左到右第一个>=target的下标
while(l<r) {
mid = (l+r)/2;
if (arr[mid]>=target) {
r = mid;
}else {
l = mid+1;
}
}
System.out.println(l);
// 方法二 返回的是最后一个=target的下标
int l2 = 0;
int r2 = arr.length-1;
int mid2 = 0;
while(l2<r2) {
mid2 = (l2+r2+1)/2;
if (arr[mid2]<= target) {
l2 = mid2;
}else {
r2 = mid2-1;
}
}
System.out.println(l2);
}
}
7. 多维数组
创建格式:以二维数组为例
数据类型[][] 二维数组名称 = new [数组长度][]; =>内层数组可以长度不同
nums[0] = new int[] {1,2,3}
注意:
数据类型[][] 二维数组名称 = new [][数组长度];报错
Day 05
1.面向对象
1.1 概念理解
面向对象是指把相关的数据和方法组织为一个整体来看待,从更高层次来进行系统性建模,面向对象关注的是具备功能的对象;区别于面向过程
1.2 三大思想
1)OOA:面向对象分析
2)OOD:面向对象设计
3)OOP:面向对象编程
1.3 三大特征
封装性:所有的内容对外部不可见
继承性:将其他的功能继承下来继续发展
多态性:方法的重载本身就是一个多态性的体现
2.类与对象
1.1 两者关系
类表示一个共性的产物,是一个综合的特征,而对象是一个个性的产物,是一个个体的特征
类必须实例化成对象才可以使用,对象的所有操作都在类中定义
类由属性和方法组成:
属性相当于特征 方法相当于行为
1.2 类与对象的创建
类的定义格式
class 类名称{
成员属性;
成员方法;
}
类必须编写在.java文件中
一个.java文件可以存在很多个类但是只能存在一个public的类,作为整个文件对外的公共类存在
.java文件的文件名必须与public修饰的类名完全一致
对象的创建格式
一个类想真正的操作则必须依靠对象,对象的定义格式如下
类名 对象名 = new 类名();
注意:同一个package里面的.java文件不能有命名相同的class
1.3 属性与方法
属性定义格式
数据类型 属性名;
String name;
int age;
char sex;
1)属性定义并赋值:
数据类型 属性名 = 初始化值;
2)对象属性赋值格式
对象名.属性名 = 值;
3)访问类中的属性或者方法
对象名.属性名 对象名.方法名
4)方法的定义格式
权限修饰符 返回类型 方法名称(形式参数列表){
方法体;
return 返回值;
}
5)方法的调用格式
对象名.方法名称(实际参数列表);
注意:这里的return代表方法的结束 后续代码不再执行
void xxx(){
if(true){
return;
}
}
1.4 对象创建时的内存细节
Book b1 = new Book();
Book b2 = b1;
b1 b2 都指一个对象
这时更改b2的属性值,b1相应的属性值也随之变化
1.4.1 栈
1)Java栈的区域大概2M,特点是存取速度特别快
原因是:
栈内存,通过栈指针来创建和释放空间,指针向下移动创建新的内存空间,向上移动释放内存。这种移动方式必须要明确移动的大小和范围
2)Java中一个线程一个栈区,每一个栈的元素都是私有的,不被其他栈所访问。
栈内的元素先进后出,栈中的数据大小与生存期都是确定的,缺乏灵活性
3)存储的是:
基本数据类型的数据 以及 引用数据类型的引用
还有对象内存地址的引用
1.4.2 堆
1)存放的是类的对象
2)使用堆内存时不必关注堆内存中需要开辟多少储存空间,也不需要关注内存占用时长
Book b1 = new Book();
=》这时整个Book类就被加载到了方法区中
栈内存存放的是对象的名称以及基本数据类型的值,所以栈中存储Book b1 默认值null
new Book()在堆内存中开辟空间,创建了一块内存,类型叫Book,内存地址用16进制表示
内存地址赋值给栈内存中的b1=》即栈内存中存储的是地址的引用
在堆内存中存储了对象的属性值
如果
Book b2 = b1 则b2的地址与b1的地址引用还是相同的
结构体结束之后栈中元素后进先出释放
当堆内存中的对象没有任何引用时则GC将其回收
Book b1 = new Book();
b1.name = "金苹果";
b1.info = "讲述了果农辛勤种植金苹果的过程";
//堆内存中 存入class b1 栈内存中存入地址
Book b2 = new Book();
b2.name = "银苹果";
b2.info = "讲述了果农辛勤种植银苹果的过程";
//堆内存中 存入class 21 栈内存中存入地址
b2 = b1;
//b2的内存地址时b1的内存地址 指向堆内存中的b1 b2没有引用 则GC垃圾回收
b2.name = "铜苹果";
1.4.3 方法区(待补)
存放类信息 类的方法 接口等引用数据类型
可以看到在方法区里的class文件信息包括:magic number,版本号,常量池,类,父类和接口数组,字段,方法等信息,其实类里面又包括字段和方法的信息。
常量池里包括String 和 基本数据类型 等
1.5 构造方法
1.5.1 概念
作用:用于object 的初始化
执行时机:在创建对象时自动调用
所有的Java类都至少存在一个构造方法
如果一个类没有明确编写构造方法则编译器会自动生成一个无参数的构造方法,构造方法中没有代码
注:Java中的构造方法应该相当于python中的__inti__
1.5.2 定义格式
1)无返回值类型声明
2)方法名称与类名完全相同
1.5.3 设计
1)自定义无参数构造方法
2)当类中有非常量成员变量时,建议提供两个版本的构造方法,一个是无参构造方法,一个是全属性做参数的构造方法。同时提供两个
全属性的构造方法即包括所有变量
3)当类中所有成员变量都是常量或者没有成员变量时,不提供构造较好
1.6 方法的重载
一个类中定义的方法是允许重载的(相同的方法名称)
1)相同的方法名称
2)参数列表长度或者参数列表类型 或者参数顺序不同
3)与返回值类型无关
调用的时候只会调用名称加类型都正确的方法
class Math{
int sum(int x, int y){
int z = x +y ;
return z;
}
double sum(double x, double y){
double z = x + y;
return z;
}
}
在主函数里调用的时候
public static void main(String[] args){
Math m = new Math();
int num = m.sum(100,500);
double num2 = m.double(10.2,24.3);
}
1.7 构造方法的重载
一个类, 可以存在多个构造方法 :
参数列表的长度或数据类型不同可完成构造方法的重载
1.8 匿名对象
1)没有对象名称
2)只能使用一次 如果用两次以上需要命名
正确:
int num = new Math2().sum(100,200);
错误:
new Person().name = "zhansan"; 堆内存开辟一段空间 age = 0
new Person().age = 18;堆内存开辟一段新的空间 与上地址不同 name = null
new Person().say();堆内存开辟一段新的空间 与上两个地址不同 name = null age = 0
Day 06
1. 封装
1.1 概念
封装:为了保护或者防止代码无意识被破坏
保护成员属性,不让类以外的程序直接访问和修改
关键字:private
class Person{
private int age;
private String name;
}
在main方法中如果
Person p = new Person();
p.age = 18;
p.name = "xiaoming";是无法操作的
这个时候解决办法:提供一个可供操作的方法
class Person{
private int age;
private String name;
//设置
void setAge(int age2){
if (age2<0||age2>150){
System.out.println("年龄不合理,自动设置为1");
age = 1;
}else{
age = age2;
}
}
//访问
int getAge(){
return age;
}
}
1.2 封装原则
隐藏对象的属性和实现细节,仅对外公开访问方法,并控制访问级别
注:在开发中为了避免出现逻辑错误,应该对所有属性封装,并为其提供setter getter 方法进行设置和取得权限
2. this 关键字
类比:
Java的this相当于python的self代表的是当前对象
this可以调用属性也可以调用方法
class Person{
private String name;
private int age;
Person(){
}
Person(String name, int age){
this.name = name;
this.age = age;
}
}
在主函数中
Person p = new Person();
// 这里不传参,用的是无参构造函数
// 如果想要一个默认值 则应有
Person(){}
=>
Person(){
this("默认姓名",1); //这里无参的通过this调用了两参的
System.out.println();//写在前面则报错
}
注意:调用类中的方法或者构造方法时,调用的代码必须编写在构造方法的第一行 如上
先构建对象 构建完对象之后再对对象进行操作
3. static
eclipse 中 option+command+s 可以选getter和setter的创建
static表示静态可以用来修饰成员变量和成员方法 存储于方法区, 所有的对象都有这块地址
static主要作用在于创建独立于具体对象的域变量或者方法,而static关键字修饰的方法或者变量不需要依赖于对象进行访问,只要类加载了就可以通过类去访问
可以把非静态修饰的属性理解为对象的属性 即实例属性
而静态的修饰的属性为类的属性
静态修饰的方法也是加载类就已经加载到内存了
静态修饰的方法被调用时有可能对象还未创建 非静态必须通过对象调用
注意:访问时静态资源不能调用非静态,非静态可以访问静态
如果不使用static:
package day02_test;
public class Demo4 {
public static void main(String[] args) {
Emp e1 = new Emp("a","beijing");
Emp e2 = new Emp("b","beijing");
Emp e3 = new Emp("c","beijing");
Emp e4 = new Emp("d","beijing");
e1.setRegion("tianjin");
e2.setRegion("tianjin");
e3.setRegion("tianjin");
e4.setRegion("tianjin");
}
}
class Emp{
private String name;
private String region;
Emp(String name,String region){
this.name = name;
this.region = region;
}
Emp(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
};
void say(){
System.out.println("员工姓名: "+name+"员工所在地: "+region);
}
}
如果使用static
package day02_test;
public class Demo4 {
public static void main(String[] args) {
Emp.region = "北京";
Emp e1 = new Emp("a");
Emp e2 = new Emp("b");
Emp e3 = new Emp("c");
Emp e4 = new Emp("d");
e1.say()
e2.say()
e3.say()
e4.say()
}
}
class Emp{
private String name;
static String region;
Emp(String name,String region){
this.name = name;
this.region = region;
}
Emp(String name){
this.name = name;
}
Emp(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
};
}
4. package
4.1 概念
功能相似或有相关关系的类或者接口放到一个包里方便类的查找和使用
不同包中的类的名字可以相同,当同时调用两个不同包中的相同类名的类时应该加上包名
包也有访问权限 拥有包访问权限的类才能访问某个包的类
4.2 规则
包的名称:所有字母都小写单词与单词直接用.隔开,一般为"com.公司名.项目名.模块名。。。。"
=》实际上就是文件夹套文件夹
在.java文件首部必须填写类属于哪个包
4.3 导包
import
lang不用导包
5. 权限修饰符
private :可以封装的更合理更极致
public:跨资源跨包访问
6. 代码块
普通代码块:普通流程中的代码块
构造代码块:随着对象的每次创建,执行一次,且执行在构造方法之前;区别于构造方法的是无论用户调用哪一个构造方法构造代码块都必然执行
单独一对{}里代码
静态代码块:随着类的加载(第一次使用),静态代码块执行=》类只加载一次,所以静态代码只执行一次,先执行
面试题:构造方法与构造代码块以及静态代码块的执行顺序:
静态代码块-》构造代码块=》构造方法
7. main方法
public static void main(String[] args)
public:权限操作符,表示公共的内容,可以被所有的操作调用
static:静态方法,可以由类名直接调用
void:无返回值
main:系统规定的名称
String[] args:接收参数的字符串数组,在执行java命令试传入参数并以空格分隔