一、第一天
1.安装linux
首先安装VM虚拟机(安装于英文路径下)
注意:Linux系统没有window系统中的盘符的说法
/swap 交换分区 1028/2048M
/boot 启动分区 520/1024
/根 剩余的空间
2.进入CentOS
建议使用普通管理员身份进入
3.Linux基础命令
ls 显示当前目录下的文件和文件夹
pwd 显示当前目录
cd 进入某一文件夹
clear 清屏
cat 观看某个文件内容
4.Linux文件系统
|–/ 根目录,类似于window的各个盘符号
|-- bin # 可执行的二级制文件()
|-- boot # 系统启动的引导文件
|-- dev # 硬件设备文件
|-- etc # 系统配置(经常配置)
|-- home # 除root外其他用户的主目录
|-- proc # 虚拟文件系统,存放当前内存的映射
|-- usr # 用于存放系统应用程序,比较重要的
|-- var # 用于存放运行时需要改变数据的文件
|-- lib\lib64 # 存储一些本地库文件
|-- mnt # 挂载镜像数据
|-- temp # 临时文件夹
5.常见命令
帮助命令:
command --help # 调用命令的帮助文档
man command # 显示命令的详细使用文档
info command # 类似于man命令
table键进行命令提示和补齐
系统信息命令:
uname
uname -a
uname -r
uname -m
……
cat 文件 # 查看文件内容
cat /etc/redhat-release # 查看内核信息
cat /etc/issue
cat /proc/version # 查看系统信息
二、第二天
1.两个基础命令
Ctrl + r # 命令终端能够查找以前输入的命令
Ctrl + c/z # 终止终端命令
2.终端
[liujianhong@localhost ~]$
[登陆用户的名称@主机名称 所在位置]$
3.
hostname 查看主机名称
su 用户名 切换用户(不加则默认切换为root)
hostname 主机名 临时修改主机名称
hostnameetcl set-hostname 主机名 永久修改主机名
ifconfig
ip addr 查询ip地址
ping 查询网络连通性
ls-a 显示路径下所有隐藏文件
ls-l 查询数据
- 文件 d 文件夹 l 链接
wrx 表示写读执行
date 获取系统时间
ps 静态查看进程
top 动态查看进程
ps-aux 显示所有进程
ps-ef|grep (进程) 过滤某个进程是否存在(|管道grep过滤)
pstree 以树形结构显示进程之间的关系
touch(文件名) 新建文件
mkdir 创建文件夹
mkdir -p xx/xx 多级目录下创建文件夹
rm 删除命令
rm-f 强制删除
echo 输出命令
cat/tac 查看内容
cp 复制
scp 远程复制
mv 剪切/重命名
find -name path 用过对应路径查询符合要求的文件
cat/tail-f 静态/动态显示数据
which/whereis 查询命令的位置
netstat 查询网络及使用端口情况
kill 杀死进程
kill-9 强制杀死进程
halt 关机
reboot 重启
exit 退出
logout 注销
三、第三天
1.常用命令
sudo 临时获得管理员权限
init (0-6)
0 关机
3 无界面系统
5 有界面系统
6 重启
tar -cvf(文件名)(所压缩的所有文件) 归档(压缩)
tar-xvf(文件名) 解归档(解压)
综合命令:tar-zcvf (文件名)(所有文件) 归档
tar-zxvf(文件名) 解归档
文件权限
rwx 读写执行
u 用户g 组o 其他人
权限名:w:2 r:4 x:1
chmod(用户)+/-(权限名)(文件名) 增加/减少某用户的某个权限
chmod xxx (文件名) 同时修改三类用户的权限
2.三种虚拟机网络配置
1、桥接:就是将虚拟机中的电脑当做真正的电脑使用,宿主机和虚拟机中共同连接到一个局域网中
2、readonly,只读模式:这种模式和nat模式很像,唯一的缺点就是虚拟机上电脑无法上公网
3、nat
3.vi/vim编辑器
Linux内置文本编辑器,作用是创建、编辑文档
命令:vi/vim 文件名 创建、编辑文档
三种模式:命令模式、编辑模式、操作模式
set nu 显示行号
set nonu 取消行号
命令模式:
:q 不保存数据退出
:q! 不保存强制退出
:wq 保存并退出
:wq! 强制保存并退出
:w 保存数据,不退出
:w! 强制保存数据,不退出
:x 会自动判断是否需要保存数据,并且退出
/ 从上而下检索内容
? 从下而上查找内容
操作模式:
yy # 复制当前行数据
p # 粘贴复制的内容
dd # 删除当前行
nyy # 复制n(数字)行
u # 撤销
ctrl + r # 返回撤销
h|向左键 # 光标左移一位
l|向右键 # 光标右移一位
k|向上键 # 光标上移一行
j|向下键 # 光标下移一行
ctrl + f # 向下跳一页
ctrl + ? # 向下跳半页
ctrl + b # 向上跳一页
ctrl + u # 向上跳半页
四、第四天
1.用户和组
用户所在文件:/etc/passwd
root: x :0:0:root:/root:/bin/bash
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
密码所在文件:/etc/shadow
root:Dnakfw28zf38w:8764:0:168:7:::
登录名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效时间:标志
用户操作
组所在文件/etc/group
root::0:root
组名:口令:组标识号:组内用户列表
useradd(用户名) 创建用户
-m 同时创建用户主目录
-M 不创建主目录
-g 指定用户加入某个组
-G 指定用户同时加入某个组
-u 手动指定用户ID值
-p 为新用户指定登录密码
usermod(用户名) 改变用户属性
-l 改变用户名
-p 修改密码
-L 锁定用户,无法登陆
-U 解锁用户
userdel(用户名) 删除用户
-r 可同时删除该用户目录
组操作
groupadd 创建组
-r 创建系统用户组
groupmod 修改组属性
-n 修改组名
-g 修改组ID
groupdel(用户名) 删除组(无法删除私有组)
口令修改
alias 原口令=新口令 临时修改口令
~/.bashrc 在该文件中咳永久修改口令
source 重新加载配置文件
软件安装与卸载
rpm
rpm -i 安装软件
rpm -Ivf 安装并显示进度
rpm -e 卸载软件(后加–nodeps强制卸载)
rpm -qa 查看安装的软件
rpm管理软件存在依赖问题,不便于使用
yum
yum install xx 安装软件
yum -y install 安装软件,并且不用再次确认
yum list installed 显示所有yum已经安装的软件
yum erase xxx 卸载软件
yum search xx 查询软件
history 显示历史命令
!command 执行上一次的命令
五、第五天
1.JAVA环境的安装与配置
window:
1、jdk 注意路径,不要出现中文,不要出现特殊符号
2、进行环境变量的配置
电脑-->属性--> 高级 --> 环境变量
创建一个JAVA_HOME的选项
1、JAVA_HOME:值就是你安装的jdk的主目录
2、在path中配置
%JAVA_HOME%\bin // H:\mytoools\java\java64\jdk1.8.211\bin
Linux:
如果使用tar包安装(店家推荐)
1、解压tar
2、进行环境变量的配置(重要,必须掌握)
如果需要配置成用户基本的环境变量(不推荐)
vim ~/.bash_profile
一般建议配置成系统级别的:
vim /etc/profile
在最后添加如下代码:
export JAVA_HOME=java的主目录
export PATH=${PATH}:$JAVA_HOME/bin
保存退出
source /etc/profile
3、测试是否成功
java -version
javac -version
第一个程序的编写
public class Test {
// main函数,是java的程序的入口
public static void main(String [] args) {
// 输出一句话,hello
Syste.out.println(“hello java!!!”) ;
}
}
当java代码书写完成,首先需要编译
javac xxxx.java // 编译一个xxx.java文件
六、第六天
1.注释
// 行注释
/*
*/块注释
\t空格
\n换行
2、变量
概念:
在程序运行过程中,允许值发生改变的量,叫做变量
定义变量:
// 在定义变量的同时赋值
数据类型 变量名称 = 变量值;
// 初始化
int a = 10;
System.out.println(a) ;
先定义
int b;
在赋值
b = 30; // int b = 30;
变量的类型
变量的命名规则:
int 变量名称 = 10 ;
在java中,变量的命名是有规范的
1、变量只能有大小写、数字、(下划线)_和$符号 组成
2、不能以数字开头
3、不能使用关键字和保留字
4、命名尽量有意义
5、变量命名推荐使用小驼峰法
userName
useAge
userAddress
还存在一中下划线法命令规范:
user_name
user_age
user_address
补充:java中类的命名一定要使用大驼峰法
Test
User
UserManger
数据类型 bit(位) b
3.基本数据类型
四类八种
整形
byte(B) 1字节
short (short int) 2字节
int 4字节
long (long int) 8字节
浮点型(小数)
float 单精度浮点数 4个字节
double 双精度浮点数 8个字节
布尔类型
boolean 值:true(真) false(假)
字符 char 值就是被单引号引起来的单个字符 ‘’
引用数据类型(复合)
对象,万物皆对象
字符串
数组
list
set
map
……
5.类型转换
由低到高的类型会自动转换
char<byte<short<int<long<float<double
强制类型转换
从高向低转换
(类型) 变量
public class Test05 {
public static void main(String[] args) {
byte a = 10;
int b = 20;
// int c = a + b ; // success
byte c = (byte) (a + b) ; // error
System.out.println©;
}
}
6.常见运算符:
1、算术运算符
+ - * /(整除) %(求余)
2、关系运算符(比较运算符)
> < >= <= (等于) !=(不等于)
3、逻辑运算符
与(并且) 或(或者) 非(取反)
&& || !
4、赋值运算符
= // 表示将右侧的值赋给左侧
+= // a += 10; <=> a = a + 10
-=
*=
/=
%=
5、自加和自减运算符
int i = 10 ;
i++;
++i;
i–;
–i;
int b = i++;
int c = ++i;
int d = i--;
int e = --i;
在加加和减减运算符中:
前加加 先自加1,在赋值
后加加 先赋值,在自加
7.从控制台输入变量
// 导入对应的包
import java.util.Scanner;
public class Test12 {
public static void main(String[] args) {
// 得到一个Scanner对象
Scanner sc = new Scanner(System.in) ;
System.out.print(“请输入第一个数:”) ;
// sc.nextInt() 表示从控制台上接受一个整形数据
int a = sc.nextInt();
System.out.print(“请输入第二个数字:”) ;
int b = sc.nextInt();
System.out.println("a + b = "+ (a + b)) ;
}
}
8.三元(目)运算符
变量 = 表达式?值1:值2 ;
int a = 10 > 20?50:80;
a?
if 10 > 20 > int a = 50
if 10 <= 20 >>> int a = 80
等同于:
if (10 > 20) {
int a = 50;
} else {
int a = 80;
}
9.程序流程:
顺序(代码都是有左而右、由上而下执行)
分支(选择)
单分支
if (条件) {
// 当条件为真的时候,执行花括号内部的代码
}
双分支
if (condition) {
// 成立
} else {
// 不成立
}
三(多)分支
if (条件1) {
} else if (条件2) {
} else if (条件3) {
} else if (条件4) {
} else {
}
第七天、
1.switch语句
switch(变量){
case 常亮1:
break;
case 常亮2:
bresk;
…
default:
}
注意:
1、switch语言一般我们需要加上break
2、如果还有其他条件,请加入default
3、switch中的变量的类型:
在jdk1.5之前,只能是char、byte、short、int
在jdk1.5之后,增加了枚举类型
在jdk1.7之后,增加了字符串(String)
目前jdk12,不支持long、浮点型
if选择语句和switch选择语句的比较:
1.switch语句只支持常量值相等的分支判断,而if语句支持更为灵活,任意布尔表达式均可;
2.switch语句通常比一系列嵌套if语句效率更高;逻辑更加清晰
switch语句和if语句的各自使用场景
1.switch建议判断固定值的时候用
2.if建议判断区间或范围的时候用
3.*用switch能做的,用if都能做,单反过来则不行
2.循环结构
for while do…while…
for
for (定义一个变量; 判断是否符号条; 条件升级) {
//循环体
}
while
while(条件) {
// 循环体
}
while
while(条件) {
// 循环体
}
注意:do while 不管条件是否符合,至少会执行一次
一般而言,主要用来做人机交互
break、continue关键字的使用
三种循环都可以用来处理同一问题。一般情况下,它们可以相互代替。下面是这三种循环语句的比较:
while和 do…while循环,只在 while后面指定循环条件,在循环体中应包含使循环趋于结束的语句(如 i++,或者 i=i+1等)。for语句中的第 3个表达式中包含使循环趋于结束的操作,设置可以将循环体中的操作全部放在表达式 3中。因此 for语句的功能更强,凡用 while循环能完成的,用 for循环都能实现。
用 while和 do…while循环时,循环变量初始化的操作应在 while和 do…while语句之前完成。而 for语句可以在表达式 1中实现循环变量的初始化。 while循环、do…while循环和 for循环,都可以用 break语句跳出循环,用 continue语句结束本次循环。 2.三种循环的使用原则
for语句是 C语言中使用最灵活的循环语句,它可以用于循环次数已知的情况,还能用于循环次数不确定的情况,但要给出循环结束条件。 while语句是一种先判断后执行的语句,如果开始不能满足条件,则可以一次都不执行循环体。 do…while语句用法和 while语句相似,也是要求先给出循环条件,经过判断后,根据循环条件是否满足,来确定是否执行循环体。
break:
1、switch 打断switch语句的作用
2、终止循环的作用
continue:
中断本次(一次)循环,进入下次循环
第八天、
1.函数:函数就是一个具有名称的代码块,一个具有特定功能的代码块,所以函数就是一个行为,一个动作,一个过程
2.函数的定义
public static 返回值的类型 函数名称([参数列表]) {
// 函数体
[return 返回结果 ;]
}
注意:java中,函数必须定义在类中
3.函数的调用:
函数名称([参数列表]);
4.函数的参数:
函数可以没有参数,函数也可以有一个参数,也可以有多个参数,
注意:需要申明参数的类型!!!
5.函数的返回值
函数可以没有返回值,请使用void关键字申明
如果函数需要返回值,return 关键字返回结果,并且函数上申明返回值的类型
注意:Java中,函数只能返回在一个值
当函数有返回值的时候,如果需要这个返回值,一定接受它。
6.函数的重载
强数据类型语言中,大多数情况下都存在函数的重载
第九天、
1.数组
一系列数据的组合
2.数组的定义
数据类型 [] 数组名称 = new 数据类型[数组大小];
3.数组元素的访问
数组名称[下标] // 下标从0开始, 最大是数组大小-1
4.数组的大小
数组名称.length属性
5.数组的遍历
一般使用循环完成数组的遍历
使用foreach语句查看数组(只能读不能写)
for(数组类型 temp:数组名){System…}
6.数组的拷贝
System.Arraycopy(数组1名,数组1起始拷贝索引,数组2名,数组2起始拷贝索引,拷贝匀速的数量)
删除数组中的某个元素,实际上也是数组的拷贝
System.Arraycopy(数组名,要删除的元素索引 + 1,数组名,要删除的元素索引,数组长度 - 要删除的元素索引 + 1)
数组元素的插入,首先进行数组的扩容(先定义一个更大的数组,然后将原数组拷贝进新数组) 和删除类似
7.数组的特点
1、数组只能存储一种数据类型
2、数组长度一旦定义,固定下来了
3、数组申请的内存区域是一段连续内存(重要)
第十天、
1.面向对象
面向对象,本质就是让电脑以人认知世界的方法来编程(构建它的世界)
2.类
是一个抽象单位,不存在,是我们通过特征和行为分门别类得到的给类别,类就是模板、是脑海中的那个模型
3.对象
万物皆对象
4.类的定义:
OO(Oriented Object):面向对象
OOP(Oriented Object Programming):面向对象的编程
OOA():面向对象分析
OOT():面向对象测试
OOD():面向对象设计
5.使用类构建对象
对象类型 对象名称 = new 类名称();
Person p1 = new Person();
6.定义类(分门别类的过程)
class 类名 {
// 类的静态特征,属性
数据类型 属性;
// 方法
public void speak() {
System.out.println("学习使人快乐~~~");
}
}
7.得到对象
类型 对象名称 = new 类型(); // 为属性赋值
对象名称.属性名称 = 属性值;
对象名称.方法名称([参数列表]);
8.变量
局部变量
定义在函数内部的变量,当函数调用完成,也就是函数弹栈之后,局部变量会消失
全局变量
在main函数中定义,在整个程序运行过程中,始终存在,不要回收的变量
成员变量
成员变量定义在类中,属于对象或者类的
成员方法:
定义在类中,所属对象或者类
什么是类?
在生活中我们也有许许多多的例子用来描述类,比如:鸟,狗,猫我们称之为动物类、盘子,刀,案板,筷子我们称之为餐具类,在java中,我们把抽取同类实体的共同性自定义扥一种数据类型称之为类。譬如,我们要定义一个人的类(那么这个人的名字,姓名,性别, 住址、、、我门都可以将它定义在同一个方法中,也就是实体类)
什么是对象?
当面向封装了具体功能类,若要使用这个类,一般情况下,在Java中需要通过创建这个类的实体来使 用。这个实体称之为对象。在开发中,我们是在不断的找封装不同功能的类。基于这些类,创建其对象, 使用这些对象完成相应的操作。
通过上面的讲解和分析得出:面向对象是基于面向过程,对象是将功能进行了封装。只要找到了具体 的类,创建出对象,就可以调用其中的具体功能。面向对象也是用来解决问题的一种思维模式。 在以后开发中,先找对象,调用对象中的具体功能。如果真的没有能够完成需求的对象,这时就自己 创建对象,并将所需的功能定义到对象中,方便以后使用
类和对象的区别是什么?
1,类是一个抽象的概念,它不存在于现实中的时间/空间里,类只是为所有的对象定义了抽象的属性与行为。就好像“Person(人)”这个类,它虽然可以包含很多个体,但它本身不存在于现实世界上。
2,对象是类的一个具体。它是一个实实在在存在的东西。
3,类是一个静态的概念,类本身不携带任何数据。当没有为类创建任何对象时,类本身不存在于内存空间中。
4,对象是一个动态的概念。每一个对象都存在着有别于其它对象的属于自己的独特的属性和行为。对象的属性可以随着它自己的行为而发生改变。
如何定义一个类、类的属性和方法?
类名 对象名 = new 类名 ();
如何创建类的对象?
class 类名{
属性1;
属性2;
属性3;
属性n;
public void 方法名(参数){
功能代码
}
}
数据类型有哪两种?区别是什么?
基本数据类型(存放在栈中) 引用数据类型(存放在堆中)
第十一天
1、属性的默认值问题
成员变量如果没有赋值,会自动的根据变量类型赋默认值
局部变量如果初始化,则无法使用,代码会报错!!!
2、构造函数
为什么有构造函数:
初始化成员变量
public 类名称() {
// 构造函数
}
注意:
1、构造函数是用来初始化成员变量的
2、构造函数名称必须和类名称一致
3、构造函数不能写返回值
4、我们通过类得到 类型 对象名称 = new 类型(); 类型()本质就是在调用构造函数
5、如果我们定义了一个类,没有写构造函数,JVM会自动帮助你生成一个无参的构造函数
6、如果我们自定义了构造函数,那么JVM就不会在自动生成无参的构造
4、this指针的使用
在java类中,存在一个this的指针,该指针会自动在创建对应对象时,默认指向对象,
所以此时this就是这个对象
5、类的成员的初始化顺序:
在初始化对象的时候,首先初始化的是属性,之后才是构造函数
方法是在调用时才初始化的,调用完成后则出栈
6、static关键字
static是java的关键字
被static修饰的成员变量最先被加载内存中
被static修饰的方法、变量都属于类本身,不属于对象,意味着可以直接通过类名来调用
静态方法中不能直接调用非静态方法(加载顺序)
被static修饰的变量,是存放在常量区
7.封装
面向对象的编程中,封装就是指,将类的属性私有化,提供公开的方法去访问的方式,叫做封装
2、怎么私有化属性?
权限访问修饰符
private // 私有 同类
默认(不写)缺省 // 只能同包 同类
protected // 受保护级别 同包 同类 子类(继承)
public // 公开的
3、如何实现封装
将属性私有化,提供公开的方法去访问和设置值
将属性私有化,通过private访问修饰符修饰
之后提供公开的get和set方法来操作属性
4、一个标准的java bean书写规范
private 修饰属性
通过公共set和get方法来访问属性
构造函数一般至少有两个,一个没有参数、一个全部参数的
第十二天、
1.eclipse的使用、
java的四大特征:抽象、封装、继承、多态
封装:将属性私有化private,提供公开的方法来访问的方式
继承:
在java中,子类继承父类,extends 关键字
当子类继承父类后,那么子类就自动的拥有了父类的一些方法和属性
继承规则:
1、public的修饰的都能被继承
2、protected修饰可以被继承
3、默认没有写,同包能访问
子类可以继承父类被public和protected修饰成员
1、在继承中,子类只能继承父类的被public或者protected修饰的方法或者属性
2、当父类方法不能满足子类的使用是,我们一般重写(覆盖)override方法
注意:重写方法是,修饰符访问权限可以扩大,不能缩小
3、子类再构造的时候,首先调用调用了父类的构造,之后才调用自身的构造
4、super是一个指针,指向子类的父类,
super() // 调用就是父类的构造
super.xxx // 调用了父类的属性或者方法
5、java中不允许使用多继承,Java是单继承机制
如果需要多继承机制,则使用接口解决
6、所有类都共有一个父类 Object
第十三天、
1.final关键字的使用
1、修饰变量,则该变量会变成常量(因为值再不能发生变化)
2、修饰方法,该方法不允许被重写(OverRide),一旦一个方法被final修饰,这个方法就是最后的方法,无法被子类重写
3、修饰类,当final修饰类的时候,该类则无法被继承,不能有子类
内部类:
类的内部定义的叫做内部类
内部类最大的作用就是,访问包含它的类的私有属性和方法
多态:
面向对象存在三大特性:封装、继承、多态
多态就是对象的多种状态
在面向对象中的多态指的是,父类引用,指向子类实例的现象,叫做多态
父类引用指向子类的实例
此时可以使用父类来代替所有的子类
final关键字
变量 —> 常量
方法 —> 无法被子类重写
类 -----> 无法被继承
抽象
父类需要存在某个,但是实现不是必须的,
主要是由子类来实现各自的功能!!!
抽象方法:没有实现的方法抽象的方法, abstract
1、如果某个类中,某个方法没有实现,则需要使用abstract将该方法申明为抽象方法
2、一旦某个类中存在了抽象方法,该类必须申明为抽象类。
3、抽象类没办法直接实例化
4、子类一旦继承了抽象类,必须要实现抽象方法,如果没有实现,则必须将子类申明为抽象类,继续向下传递这种特性
抽象类中可以普通的方法?
可以
抽象类中可以没有抽象方法吗?
可以
抽象的必要的条件:
|-- 继承
|-- 方法重写
接口
在Java中,可以使用interface关键字申明的类,叫做接口
注意:接口中的成员都必须public的,即便没有申明,也是public
接口中的方法都是抽象方法(接口中方法没有实现)
接口不能有实现了的方法(必须都是抽象方法,jdk1.8之前)
接口可以多个实现( implements TestInterface, MyInterface2)
接口可以继承接口(重点掌握)public interface MyInterface2 extends TestInterface
在jdk1.8之后,接口可以使用static或者default关键字定义实现了的方法
接口的作用:
1、约束、规定
2、对Java单继承的补充
接口和抽象类:
接口是一种特殊的抽象类
接口的命名规则:
接口包的命令规则:
1、第一种情况
1、将接口定义在包中 UserDao.java
2、接口的实现类一般方法该包的下一层 xxxxx.impl UserDaoImpl.java
2、第二种情况
将接口和实现类放在一起
IUserManager
UserManager、
第十五天、
异常
Object:
在Java,任何一个类,直接或者间接都是Objectd的子类
Object类定义在java.lang包
--------------------跟线程相关方法,后面再说------------------------------
wait() ; // 让线程进入等待状态的方法
notify(); // 唤醒线程的方法
notifyAll(); // 唤醒所有等待线程的方法
------------------------------------------------------------
clone(); // 做对象拷贝的
Class cls = getClass(); // 获取对象的字节码文件
toString();
如果没有重写对象的toString方法,当我们直接打印对象的时候
package.ClassName@hashCode值
面试题1:
请解释下 final finally finalize 三者的作用和区别
1. final
在java中,final可以用来修饰类,方法和变量(成员变量或局部变量)。下面将对其详细介绍。
1.1 修饰类
当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰,但要注意:
final类中所有的成员方法都会隐式的定义为final方法。
1.2 修饰方法
使用final方法的原因主要有两个:
(1) 把方法锁定,以防止继承类对其进行更改。
(2) 效率,在早期的java版本中,会将final方法转为内嵌调用。但若方法过于庞大,可能在性能上不会有多大提升。因此在最近版本中,不需要final方法进行这些优化了。
final方法意味着“最后的、最终的”含义,即此方法不能被重写。
注意:若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。
1.3 修饰变量
final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。类似于C++中的const。
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
在java中,String被设计成final类,那为什么平时使用时,String的值可以被改变呢?
字符串常量池是java堆内存中一个特殊的存储区域,当我们建立一个String对象时,假设常量池不存在该字符串,则创建一个,若存在则直接引用已经存在的字符串。当我们对String对象值改变的时候,例如 String a=“A”; a=“B” 。a是String对象的一个引用(我们这里所说的String对象其实是指字符串常量),当a=“B”执行时,并不是原本String对象(“A”)发生改变,而是创建一个新的对象(“B”),令a引用它。
2.finally
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。(×)(这句话其实存在一定的问题)
很多人都认为finally语句块一定会执行,但真的是这样么?答案是否定的
只有与finally对应的try语句块得到执行的情况下,finally语句块才会执行。以上两种情况在执行try语句块之前已经返回或抛出异常,所以try对应的finally语句并没有执行。
但是,在某些情况下,即使try语句执行了,finally语句也不一定执行。
我们在 try 语句块中执行了 System.exit (0) 语句,终止了 Java 虚拟机的运行。那有人说了,在一般的 Java 应用中基本上是不会调用这个 System.exit(0) 方法的。OK !没有问题,我们不调用 System.exit(0) 这个方法,那么 finally 语句块就一定会执行吗?
当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。可能有人认为死机、断电这些理由有些强词夺理,没有关系,我们只是为了说明这个问题。
finally用法特殊,所以会撤销之前的return语句,继续执行最后的finally块中的代码。
3.finalize
finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
使用finalize还需要注意一个事,调用super.finalize();
一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。
finalize() // 该方法在对象被垃圾机制回收前,最后被触发
equals() // equals 比较两个对象是否相等
equals方法底层真正比较的是两个对象的内存地址()
public boolean equals(Object obj) {
return (this == obj);
}
// equals()
在String类,我们可以直接调用equals比较两个字符串,因为String类重写Object的equals方法
hashcode() // 返回对象内存地址的hash值
最佳建议:
在编程中,一般比较对象,需要重写hashCode、equals
异常:
1、什么是异常
代码运行过程中,或者编译过程中,因为用户的不当操作,或者其他的因素干扰,
导致程序出错的现象,叫做异常
2、处理异常的目的
让程序继续运行,同时提醒用户
3、常见的异常
ArithmeticException
4、什么是异常:
子啊java中异常就是类
一旦代码出现了异常,程序就会被终止掉
5、java中处理异常的方法:
1、不处理 抛给调用者
2、使用try catch 语句块尝试着抓取异常
try:
//可能出现异常的代码
catch (XxxException e) {
// 当代码触发了异常,代码会进入到catch中
}
6、异常对象中的两个方法
// 打印异常触发的栈信息
e.printStackTrace();
// 获取异常信息
e.getMessage()
7、try catch的运行流程
8、try catch finally
try {
} catch (ArithmeticException e) {
} finally { // 一定要执行的代码块
// 不管是否存在异常,finally中的必须执行
// 资源释放等工作凡在finally
}
----------------------------------------------------------
try {
} finally {
}
1、什么是异常
2、如何处理异常
|-- 捕获异常
|-- 抛出
3、捕获异常的操作
try {
// 可能发生异常的代码
} catch(xxxException e) {
// 异常发生时,需要执行的代码
} finally {
// 必须执行的代码
}
4、try语句块的顺序
5、常见的异常
ArithmeticException
NullPointException
ClassCastException
下标越界异常
…
6、使用多个catch进行多次异常的捕获
注意:当捕获到一个异常后,其他异常就没法办法捕获了 7、异常继承关系
Throwable
8、异常抛出(throws关键字的使用)
第二种处理异常的方式
在方法的名称后面使用throws 抛出异常,将可能出现的异常抛给调用者
有调用者来处理异常,如果调用者也不处理异常,则继续向上抛,最后如果都不处理
则会有main函数抛给JVM
9、自定义异常的使用
当jdk提供的异常不够我们使用的时候,我们需要自定义异常
建议继承RuntimeException
10、异常类型
编译型异常: 在编译时,必须处理的异常 Exception
非编译型异常: 在运行的是,抛出的异常, RuntimeException 或者它的子类
11、人为抛出异常
人为抛出异常,一般都是为低层为高层传递信息
第十六天、
Java有8种基本数据类型,为什么又要出现对应的8种包装类:
1、Java的8种基本数据类型不支持面向对象编程机制
2、8种基本数据类型不具备“对象”的特性:没有成员变量、方法可供调用
3、例如:某个方法需要Object类型的参数,但实际需要的却是2、3这种值,只靠基本的数据类型无法转换成Object参数传递过去
4、为解决8种基本数据类型不能当成Object类型使用的问题,Java提供了包装类的概念:
8种基本数据类型与对应的包装类:
byte ------------------------> Byte
short -------------------------> Short
int -------------------------> Integer
long -------------------------> Long
char -------------------------> Character
float -------------------------> Float
double -------------------------> Double
boolean -------------------------> Boolean
5、基本类型与包装类之间的转换(JDK1.5之前):
5.1、通过包装类对应的构造器实现
5.2、通过传入一些字符串参数,来构建包装类对象,如:
Integer a = new Integer(“5.5”);
5.3、如果想获得包装类对象中包装的基本类型变量,可以用包装类提供的.xxxValue()方法
代码示例:
public class WrapperClass{
public static void main(String[] args){
//-构造器方法定义Integer包装类a,并赋值
Integer a=new Integer("5");
System.out.println(a);
//-构造器方法定义Double包装类b,并赋值
Double b=new Double("5.5");
System.out.println(b);
//-通过包装类.xxxValue()方法,从包装类对象中获取基本类变量
int c=a.intValue();
System.out.println(c);
double d=b.doubleValue();
System.out.println(d);
}
}
运行结果:
6、基本类型与包装类之间的转换(JDK1.5之后):
6.1、自动装箱(Autoboxing):把一个基本类型的变量,直接赋值给对应的包装类变量,或者赋值给Object变量(Object是所有类的父类,子类对象可以直接赋给父类变量----Java的向上自动转型特性)如:
Integer i=3;或Object j=4;
6.2、自动拆箱(AutoUnboxing):把一个包装类变量,直接赋值给一个基本类型的变量,如:
int a=i;
注意:int b=j;编译会报错,原因是:Java有向上自动转型特性,但不能自动向下转型,想要转要加强制转换,如:
int b = (Integer)j;
代码示例:
public class AutoBoxingUnboxing{
public static void main(String[] args){
//-自动装箱
Integer a=3;
//-自动拆箱
int b=a;
//-直接赋值给Object类型的变量,利用了Java的向上自动转型特性
Object o=true;
if(o instanceof Boolean){
//-Object类型不能直接赋值给Boolean类型,Java不能自动向下转型,如下代码会报错
//Boolean d=o;
//-想向下转型可以用强制转换方法,如下代码
Boolean c=(Boolean)o;
System.out.println(c);
}
}
}
请简述String、StringBuilder、StringBuffer之间的区别?
它们三个都是通过字符数组char[]实现,而String在在字符数组前加了final修饰,使其长度不可变.
分析一:
记住一点,String类型字符串一旦被创建,就不能被更改。
String str =new String("Hello");
str=str+"word";
首先,创建值为"Hello"的str对象,后来对str对象追加字符串“word”,形成新的str对象,咦?不是说字符串一旦创建,不能更改吗?
其实,第一行代码是我们程序员自己创建了str对象,但当执行到第二行代码时,因为str值一旦创建不能更改,而我们代码中仍然使用str这个变量名,系统内部又重新创建新的str对象,(用str="值"方式进行赋值,在编译前就会在常量池中创建好)对之前的str对象进行覆盖,而之前的str对象将由GC进行回收。
那试想,如果进行频繁的字符串更改,对内存是无比的浪费啊,而StringBuffer和StringBuilder正好解决此问题,创建一个此类对象,可以在原内存中对对象进行更改,类似于普通类对于属性的操作。
借助jvm内存分析来深入理解String
jvm为了节省字符串重复创建而造成内存浪费,特别维互一个叫常量池的区域,当使用String str ="值"形式创建字符串对象时,就会去查找常量池中有无这个的值,如有,直接引用返回,如果没有系统会在常量池创建,然后引用返回。当使用String str =new String(“值”)时,既然有new关键词,势必会在进行堆中进行new对象3步骤(1.在堆中开辟内存空间 2,调用构造器初始化对象 3.返回引用地址值),每次new都会产生新的对象。
分析二:
Sring对象的更改(主要指new方式创建),会频繁的在堆中开垦内存,造成内存浪费,效率也会大大在降低,并且会有很多脏屁股让GC去帮忙擦。 StingBuffer和StingBuilder不同,一个对象只需要开辟一块内存空间,那效率就会高很多。
但要细说StringBuffer和StringBuilder,它们在效率上应该不会有大的区别,但因为StringBuffer内中的方法,很多用了synchronized锁,所有在多线程下,会稍慢于StringBuilder.
也正因为 StringBuffer类中方法中多代有synchronized,线程安全,所有在多线程环境下,我们要舍StringBuilder而用StringBuffer
使用总结:
(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。
第十七天、
时间对象的重要性,java中如何对时间操作了?
Date(日期)
Calendar(日历)在jdk低版本中,一般我们操作时间使用Calender
SimpleDateFormat
如上的对象,在操作时间和日期时,如果处于高并发,都有可能出现线程安全问题,所以
jdk8.0之后,提供了其他替代的方案
LocalDate //日期
LocalTime //时间
LocalDateTime //日期时间
Instant
DateTimeFormatter //格式化
作业:
当时接口中定义
static方法
default方法
static方法和属性属于类的,可以直接通过类名调用
NumberFormat和DecimalFormat
NumberFormat:
数字的格式化
货币的格式化
百分比的格式化
作业:
DecimalFormat 参考PPT
importjava.text.DecimalFormat;
public class TestNumberFormat{
public static void main(String[]args){
doublepi=3.1415927; //圆周率
//取一位整数
System.out.println(newDecimalFormat(“0”).format(pi)); //3
//取一位整数和两位小数
System.out.println(newDecimalFormat(“0.00”).format(pi)); //3.14
//取两位整数和三位小数,整数不足部分以0填补。
System.out.println(new DecimalFormat(“00.000”).format(pi));// 03.142
//取所有整数部分
System.out.println(newDecimalFormat("#").format(pi)); //3
//以百分比方式计数,并取两位小数
System.out.println(new DecimalFormat("#.##%").format(pi)); //314.16%
longc=299792458; //光速
//显示为科学计数法,并取五位小数
System.out.println(newDecimalFormat("#.#####E0").format©); //2.99792E8
//显示为两位整数的科学计数法,并取四位小数
System.out.println(newDecimalFormat(“00.####E0”).format©); //29.9792E7
//每三位以逗号进行分隔。
System.out.println(newDecimalFormat(",###").format©); //299,792,458
//将格式嵌入文本
System.out.println(newDecimalFormat(“光速大小为每秒,###米。”).format©);
}
}
常见的设计模式
GOLF提出23设计模式,企业级开发架构而言
单例(Singleton) 单个实例,只有一个对象,不能出现多个对象
|-- 懒汉模式
public class User {
public static User user;
// 首先将构造函数私有
private User() {
}
public static User getInstance() {
if (user == null) {
user = new User();
return user;
}
return user;
}
}
|-- 饿汉模式
public class User {
public static User user = new User();
// 首先将构造函数私有
private User() {
}
public static User getInstance() {
return user;
}
}
工厂设计模式:
|-- 简单工厂
将对象的创建交给工厂,有工厂统一管理对象的创建
位运算
二级制
原码
反码
补码
位运算
与 或 异或运算
5|2 // 只要一者为真,则为真
3&5 // 两者都为真,则为真
3^5 // 两者相反则为真
堆和栈
getSum(100)
作业:使用递归完成1~10的积
堆和栈
java -Xss // 指定栈大小
-Xms // 堆的初始化大小
-Xmx // 堆的最大值
第十八天、
对于大量数据的操作:
1、数组操作
|-- 数组只能存储一种数据类型
|-- 一般数组大小固定
|-- 一块连续内存
|-- 访问的速度快
|-- 增删改比较麻烦
List 链表
|- ArrayList
基于数组实现的链表
查询速度快
更新速度慢
面试题:|-- ArrayList 如何添加数据过程:
ArrayList默认大小是10
MAX_SIZE = 10
Object[] aa = new Object[MAX_SIZE];
size
aa.add(5);
在ArrayList添加数据的过程:
判断插入是否已经大于等于数组长度,如果已经成立,需要扩容,默认初始大小10
每次扩容为原有大小1.5倍,扩容完成
在进行数据插入
面试题:ArrayList和LinkedList的区别:
LinkedList是典型的双向链表
1、ArrayList查询速度快,LinkedList查询速度慢
2、ArrayList增删改速度慢,LinkedList增删改速度快
泛型:强制规定:在以后使用集合,必须使用泛型
早晨内容:
集合(Collection)
五个接口:Interable(可迭代的) Collection List Set Map
五个类: ArrayList LinkedList
Iterator Iterable
Set 集合
Set有两大特点:
1、无序
2、不能重复
Map 二维表
{ps=200, addr=100000, age=1000, username=2}
Map结构:
jdk1.8之前:
数组 + 链表组成
jdk8及其以后:
数组 + 红黑树的实现
User UserManger
IUserManger
User load(int id);
User load(String username);
void add(User user);
void delete(int id);
void update(User user);
void login(User user);
List<User> list();
第二十天、
File类
文件对象,java用来封装文件的
File f = new File(String path);
File f = new File(String parent, String filename);
File f = new File(File parent, String filename);
File f = new File(Uri url);
f.createNewFile(); # 创建文件或者文件夹
f.mkdir() # 常见目录
f.mkdirs() # 递归创建多级目录
f.exists() # 是否存在
f.existsOnExit() #
f.delete() # 删除
f.getAbsolutePath() # 获取f对象的绝对路径
f.getName() # 获取文件名称
f.getParent() # 获取父级路径
f.getFreeSpace() # 剩余空间
f.getUsableSpace() # 可用空间
f.getTotalSpace() # 总空间大小
f.getParentFile() # 获取父级File对象
f.renameTo() # 重命名或者移动文件
f.isFile() # 是否文件
f.isDirectory() # 是否是文件夹
f.list()
f.list(FilenameFilter ff)
f.listFiles()
f.listFiles(FilenameFilter ff)
案例练习:遍历磁盘的所有文件 打印所有的绝对路径
2、IO流的分类,一个简单的FileInputStream的案例,说明流使用的步骤
|-- 流的分类
|- 通过流的方法:
|-- 输入流 字节输入流,默认都继承InputStream类,字符输入流,Reader
|-- 输出流 字节输出流,默认都继承OutputStream类,字符输出流,Writer
|-- 安装功能划分:
|-- 节点流 直接使用new能够得到对象的流
|-- 过滤流 过滤流重要用于装饰节点流,过滤流就是用来装饰节点流的
|-- 根据流的数据类型
|-- 字节流
|-- 字符流
|-- 转换流
在Java IO包,大量使用了一种设计模式,装饰者设计模式
3、文件输入输出流的使用(文件的复制和拷贝)
4、节点流和过滤流,案例拷贝数据,演示没有关闭流出现的问题,讲解装饰者设计模式的使用
5、DateInputStream DateOutputStream演示保存字节对象
6、字符流(Reader和Writer)
7、转换流(InputStreamReader和OutputStreamReader)