目录
开发中如何选择使用try-catch-finally 还是使用throws?
LocalDate,LocalTime,LocalDateTime
1. Eclipse中的快捷键
* 1.补全代码的声明:Alt + /
* 2.快速修复:Ctrl + 1
* 3.批量导包:Ctrl + Shift + o
* 4.使用单行注释:Ctrl + /
* 5.使用多行注释:Ctrl + Shift + /
* 6.取消多行注释:Ctrl + Shift + \
* 7.复制指定行的代码:Ctrl + Alt + down 或Ctrl + Alt + up//上下键
* 8.删除指定行代码:Ctrl + d
* 9.上下移动代码:Alt + up 或 Alt + down
* 10.切换到下一行代码空位:Shift + 回车
* 11.切换到上一行代码空位:Ctrl + Shift + 回车
* 12.查看源码:Ctrl + 鼠标指定的结构 或 Ctrl + Shift + t
* 13.退回到前一个编辑的页面:Alt + left
* 14.进入到下一个编辑页面:Alt + right
* 15.光标选择指定的类,查看继承树的结构:Ctrl + t
* 16.复制代码:Ctrl + c
* 17.撤回代码:Ctrl + z
* 18.反撤回代码:Ctrl + y
* 19.剪切:Ctrl + x
* 20:粘贴:Ctrl + v
* 21.保存:Ctrl + s
* 22.全选:Ctrl + a
* 23.格式化代码:Ctrl + Shift + f
* 24.选中数行整体往后移:Tab
* 25.选中数行整体往前移:Shift + Tab
* 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:Ctrl + o
* 27.批量修改指定的变量名、方法名、类名等:Alt + Shift + r
* 28.选中结构中的大小写的切换:变成大写:Ctrl + Shift + x
* 29.选中结构中的大小写的切换:变成小写:Ctrl + Shift + y
* 30.调用生成getter/setter/构造器等结构:Alt + Shift +s
* 31.显示当前选择资源(工程 or文件)的属性:Ctrl + enter
* 32.快速查找:参照选择中的Word快速定位到下一个:Ctrl + k
* 33.关闭当前窗口:Ctrl + w
* 34.关闭所有窗口:Ctrl + Shift + W
* 35.查看指定结构使用过的地方:Ctrl + Alt + g
* 36.查找与替换:Ctrl + f
* 37.最大化当前的View:Ctrl + m
* 38.直接定位到当前行的首行:Home
* 39.直接定位到当前行的末尾:End
————————————————
2.输出
System.out.print("");
System.out.println("");//自动换行
int sum = 3.1415926;
System.out.println(""+sum);
System.out.println("%.2f",sum);//四舍五入
3.输入
Scanner in = new Scanner(System.in);
Scanner in = new Scanner(System.in);
System.out.println(in.nextline());
*对于char类型的获取,Scanner没有相关的方法,只能获取一个字符串
4.数据类型
常量:final int ...
long l = 1233728208038L;
整数默认int,小数默认double
5.计算
System.out .println(2+3+"=2+3="+(2+3));
int price,amount;
amount = in.nextInt();
price = in.nextInt();
System.out.println(amount+"-"+price+"="+(amount-price));
6.优先级
7.类型转换
①int->double: 自动/(double)( )
②double->int: (int)( )
double a;
int b;
b = in.nextInt();
a = in.nextInt();
a = in.nextDouble();
b = (int)(a);
8.比较、判断
Scanner in = new Scanner(System.in);
int amount=in.nextInt();
System.out.println(amount>=10);
//输入:10
//输出结果:true
==和!=优先级最低,连续的运算符从左到右执行判断
浮点数比较
System.out.println(Math.abs(f1-f2),0.00001);//判断两个浮点数是否相等
if(amount>=0)
System.out.println("fighting");
if-else
if-else-if
switch-case
9.循环
for循环
while循环
do-while循还
*建立随机数
int count = (int)Math.random()*100 //[0,1)->[0,100)
*带标签的break&&continue
退出多重循环
(在循环前可以放一个标号来表示循环,带标号的break和continue对那个循环起作用)
OUT://标号
for(i=1;i<n;i++)
{
for(j=0;j<n;j++)
{
for(k=0;k<n;k++)
{
if(i+j+k>n)
break OUT;
}
}
}
*boolean
boolean isprime = true;
boolean[] a = new boolean[100];
isprime = false;
if(isprime)
{
System.out.print(" ");
}
10.数组
*创建数组
*数组长度
int[] number = new int[100];//创建数组
int[] score = {1,2,3,4,5,6};
int[][] a = new int[2][3];
number[i] = a;
for(i=0;i<number.length;i++)//number.length为数组长度
String arr = new String[2][];
arr[0] = new String[4];
*数组变量
数组变量是数组的管理者而非数组本身
数组创建出来后必须交由数组变量管理
数组变量之间的比较可以判断是否为同一数组(地址相同)
int[] a1 = new int[10];
int[] a2 = a1;
如果要复制数组,必须用遍历!!!
数组的输出
1.遍历输出
2.直接数组名输出:System.out.println(数组名);//只有char型可以用,否则会输出内存地址。
3.带格式输出:System.out.println(Arrays.toString(数组名));//适用任意类型数组,但输出的内容是带格式的,元素与元素之间有逗号隔开。
*for-each循环遍历
for(<类型><变量> : <数组>)...
!!!不能改变数组的值
for(int k : a)//每次循环将a里面的值赋值给k (第一次:k=a[0]...)
{
if(k=x)
...
}
11.字符
char c = \u0040
// /u指Unicode编码,0040是八进制
*\t :到下一个表格位,上下对齐(不是空四个)
12.包裹类型
对于基本数据类型,Java提供了对应的包裹(wrap)类型。这些包裹类型将一个基本数据类型的数据转换成对象的形式,从而使得它们可以像对象一样参与运算和传递。
除了int和char以外,包裹类型就是把基本类型的名字的第一个字母大写。在Java的系统类库中,所有第一个字母大写的,都是类的名字
*包裹类型的用处:
获取该类型的最大最小值
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
* . :当需要用一个类或者对象做事情的时候,用.坐运算符
a.length
Integer.MAX_VALUE
*Character:
System.out.println(Character.isdigit('1'));
System.out.println(Character.toLowerCase('A'));
*Math类 :
abs / pow / random(获取0-1之间的数) / round(四舍五入)
13.字符串
*字符串变量:
String str1 = new String("a string");
String str2 = "hello";
char[] str3 = new char[5];
System.out.println("hello"+"world");
System.out.println(1+2+"hello");
//创建了一个String的对象
//用“a string”初始化这个对象
//创建管理这个对象的变量s
//让s管理这个对象
String不能用for-each循环来遍历
char可以
*字符串连接
+ : 当这个+的一边是字符串而另一边不是时,会将另一边表达为字符串然后做连接(八种数据类型
String s = "Hello";
int num = 1002;
String w = s + num;//boolean只能与字符串做连接运算
System.out.print(s+num);
System.out.println("* *");//* *
System.out.println('*'+'\t'+'*');//93,转换成ASCLL做加法
System.out.println('*'+"\t"+'*');//* *
*输入字符串
Scanner in = new Scanner(System.in);
String s;
s = in.next();
对象变量的赋值
*比较
==:比较是否是同一个
equals:比较是否具有相同的内容
compareTo:比较两个字符串谁大谁小
String s = reader.getInput();
if(input.equals("bey")
{
...
System.out.println(s1.compareTo(s2));
System.out.println("abcd".compareTo(s2));
//如果s1<s2,那么结果为负,s1==s2,结果为0,s1>s2,结果为正
System.out.println(s1.compareToIgnoreCase(s2));
//不区分大小写来比较大小
*字符串操作
字符串是对象,对它的所有操作都是通过“ . ”这个运算符来进行
格式:字符串.操作
*获取String的长度
length()函数:str.length
String str = "";//length为0
String ser;//ser.length Error!
System.out.print(str.length());
*访问字符串里面的单个字符
charAt(index):s.charAt(index)
//返回在index上的单个字符,index∈[0,length-1],不能用for-each循环来遍历字符串
(for-each只能对于数组)
*遍历循环字符串
for(int i=0;i<s.length();i++)
{
...
*得到子串
[0,...]
System.out.println(s.substring(n));//得到从n号位置到末尾的全部内容
System.out.println(s.substring(b,e));//得到从b号位置到e号位置之前的内容[b,e)
*寻找字符
String s = "0123456789";
System.out.println(s.indexOf('4'));
System.out.println(s.indexOf("234"));
*其他String操作
所有的字符串都是不可变的,对它们的操作的结果都是制造新的字符串出来(不是对字符串本身做变化)
*在switch-case中使用字符串
switch(s)
{
case"this":...
case"that":...
...
}
14.函数
String s = "hello";
int i = s.length();
Ssytem.out.print(s+"bey");
//这些都写对象在执行函数
函数是一块代码,接收0个或多个参数,做一件事情,并返回0个或一个值
public static <返回类型> <函数名>(<参数>)
{
...
}
*传入的参数类型不匹配
当函数期望的参数类型比调用函数时给的值的类型宽(字节长度)的时候,编译器能悄悄替你把类型转换好
byte-->char-->short-->int->long-->float-->double
*当byte,char,short三种变量做运算时,结果类型要为int
当函数期望的参数类型比调用函数时给的值的类型窄的时候,需要你写强制类型转换
(int)5.0
当函数期望的参数类型与调用函数时给的值的类型之间无法转换的时候-->不行!
其他
1在CMD中编译运行java
编写:将java代码保存在以“.java”结尾的源文件中
编译:使用javac.exe命令编译我们的java源文件,格式:javac 源文件名.java
运行:使用java.exe命令解释运行我们的字节码文件,格式:java 类名
在一个java源文件中可以声明多个class,但是,最多只能有一个类声明为public,而且要求声明为public的类的类名一定要与源文件名相同
2关于进制
二进制:0,1,逢二进一,以0b或者0B开头
十进制
八进制:0-7,满8进1,以数字0开头
十六进制:0-9以及A-F,满16进1,以0x或0X开头,此处A-F不区分大小写
Arrays工具类的使用
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组的各种方法
单元测试
步骤
1.选中当前工程 - 右键选择:build path - addlibraries - JUnit 4 - 下一步
2. 创建Java类,进行单元测试。此时的Java类要求,此类是public的,并且提供公共的无参的构造器
3.此类中声明单元测试方法。此时的单元测试方法,方法权限是public,没有返回值,没有形参
4.此单元测试方法上需要声明注解:@test,并在单元测试类导入import org.junit.Test
5.声明好单元测试方法以后,就可以在方法体内测试相关的代码
6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnitTest
7.没有异常,绿条;有,红条、
8.直接写,然后加。。。。
内存解析
栈:存局部变量
堆:new出来的结构:对象,数组
方法区:类的加载信息,静态域,常量池
面向对象
三条主线:
java类及其类的成员:属性,方法,构造器,代码块,内部类
面向对象的三大特征:封装性,继承性,多态性,(抽象性)
其他关键字:this,super,static,final,abstract,interface,package,
1面向过程(POP)与面向对象(OOP)
概念
面向过程(Procedure Oriented Programming):强调的是功能行为,一函数为最小单位,考虑怎么做。
面向对象(Object Oriented programming):将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
三大特征
封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)
2Java基本元素:类和对象(面向对象的核心概念)
概念
类(Class):对一类事物的描述,是抽象的,概念上的定义。
对象(Object):是实际存在的该类事物的每个个体,因而也称为实例
*面向对象的程序设计重点是类的设计,类的设计其实就是类的成员的设计
*java中用class来描述事物,
常见的类的成员
属性:对应类中的成员变量(field)
行为:对应类中的成员方法(method)
一个类在另一个类中声明,这是关联关系
//Account.java
class Account{
private int account;
}
//Bank.java
class Bank{
private Account account;
}
3对象的创建和使用
1.创建类,设计类的成员
2.创建类的对象
3.通过“对象.属性”/“对象.方法”调用对象的结构
public class XXXX {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建Person类的对象
Person p1 = new Person();
//调用属性
Scanner in = new Scanner(System.in);
p1.language = in.next();
p1.is = true;
//调用方法
p1.lang(p1.language);
p1.lang("China");
p1.eat();
//多个对象
Person p2 = new Person();
Person p3 = p1;//将p1的地址赋给p3
}
}
//类的创建
class Person{
String language;
boolean is ;
public static void eat() {
System.out.print("eat");
}
public static void lang(String language) {
System.out.println(language);
}
}
*如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性(非static的)
对象的内存解析
匿名对象
没有显示的赋给一个变量名,只能调用一次
public class test{
public static void main(String[] arg){
Phone p1 = new Phone();
p1.eat;
p1.play;
new Phone();
new Phone.eat();
new Phone.play();//两个不同的变量
Use(new Phone());//匿名对象的一般使用
}
public void Use(Phone phone){
phone.eat();
phone.play();
}
}
class Phone{
public void eat(){
System.out.print("eat");
}
public void play(){
System.out.print("play");
}
}
4类的成员之一:属性
属性(成员变量)vs 局部变量
相同点
1.定义变量的格式:数据类型 变量名 = 变量值
2.先声明,后使用
3.变量都有其对应的作用域
不同点
1. 在类中声明的位置不同
属性:直接定义在类的一对{}内,不在方法内。
局部变量:声明在方法内,方法形参,代码块内,构造器形参,构造器内部
的变量。
2.关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public、缺省、protected。
局部变量:不可以使用权限修饰符。
3.默认初始化值的情况
属性:类的属性,根据其类型,都有默认初始化值。
整型:0;浮点型:0.0;字符型:0(或'\u000');布尔型:false;引用数据类型:null
局部变量:没有初始化值(在调用之前就要赋值)
4.在内存中加载的位置
属性:加载到堆空间(非static中)
局部变量:加载到栈空间
5类的成员之二:方法
Math类:sqrt()、random()...
Scanner类: .nextXxx() ...
Arrays类 ...
如何定义方法
权限修饰符 返回值类型 方法名(形参){
方法体
}
//方法的声明
public void eat(){}
public void sleep(int hour){}
public String getname(){}
public String Nation(String nation){}
6再谈方法
方法的重载(overload)
定义:在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不相同(与权限修饰符,返回值类型无关)
可变形参的方法
格式:数据类型 ...数据名称
*传入的参数个数可以为0个,1个,2个...
*可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
*可变个数形参在方法的形参中,必须声明在末尾,且只能声明一个
public class MoreXincan {
public static void main(String[] args) {
// TODO Auto-generated method stub
MoreXincan test = new MoreXincan();
test.show("hello");
test.show("hello","world");
test.show();
}
// public void show(String s) {
// System.out.print("sh");
// }
public void show(String...arg) { //(String[] arg)
System.out.print("wu");
}
public void show(int i,String...arg){
}//(String...arg,int i)是错的
**方法参数的传递机制
关于变量的赋值
变量是基础数据类型:此时赋值的是变量所保存的数据值
变量是引用数据类型:此时赋值的是变量所保存的数据的地址值
方法参数的传递机制:值传递
递归方法
public class ObjectShuzu {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student[] stu = new Student[20];//****声明Student类型的数组
for(int i=0;i<stu.length;i++) {
stu[i] = new Student();//****给数组元素赋值
stu[i].num = (int)(Math.random()*100);//给Student对象的属性赋值
}
for(int i=0;i<stu.length;i++)
{
System.out.print(stu[i].num+" ");
}
}
}
class Student{
int num;
在本类中不用重新制造对象,在本类使用其他类的属性或方法要制造对象
7OOP特征之一:封装与隐藏
高内聚,低耦合
问题引入
当我们创建一个类的对象之后,我们可以通过“对象.属性”的方式对对象的属性进行赋值。这里,赋值操作要受到数据类型和存储范围的制约。除此之外,没有其他的制约条件。但是,在实际问题中,我们往往需要给属性赋值,加入额外的限制条件。这个条件就不能在属性声明时体现,只能通过方法进行限制条件的添加,同时要避免使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的(private)---->封装性的体现
//对属性进行封装(比如腿的个数不能为负)
//对属性进行限制(比如腿的个数不能为负)
public class Restrict {
public static void main(String[] args) {
// TODO Auto-generated method stub
Animal a = new Animal();
a.name = "刘宇峥";
a.age = 11;
Scanner in = new Scanner(System.in);
int l = in.nextInt();
a.setleg(l);
System.out.print(a.name);
if(a.leg>=0)
System.out.print("是个正常人,有"+a.leg+"条腿");
else
System.out.print("不是个正常人");
}
}
class Animal{
String name;
int age;
private int leg;//腿的数量,对leg进行封装
public void setleg(int l) {//leg的接口
if(l>=0)
leg = l;
else
leg = -1;
}
public int Getleg(){
return leg;
}
}
封装性的体现
1.将类的属性私有化(private)
2.提供公共的(public)方法来获取(GetXxx)和设置(SetXxx)
四种权限修饰符
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | yes | |||
(缺省) | yes | yes | ||
protected | yes | yes | yes | |
public | yes | yes | yes | yes |
*对于class(类)的权限修饰只能用public和default(缺省)
*public可以在任意地方被访问
*default类只可以被同一个包内部的类访问
*子类对象的访问权限要大于父类的访问权限
4种权限可以用来修饰类和类的内部结构:属性,方法,构造器,内部类
8类的成员之三:构造器
构造器的作用
构建对象
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符 类名(形参列表){ }
Person p = new Person();//(new + 构造器)
3.一个类中定义多个构造器,彼此构成重载
4.一旦显式的定义了类的构造器之后,系统不再提供默认的空参构造器
5.一个类中至少有一个构造器
给属性做初始化
public class Constructor {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a=2;
Person p = new Person(a);
}
}
class Person{
//属性
int age;
//构造器
public Person() {
}
public Person(int a) {
age = a;
}
//方法
public void eat() {
System.out.print("eat");
}
}
总结属性赋值的先后顺序
(一点都不严谨,离谱)
1.默认初始化
2.显式初始化
3.构造器中初始化
4.通过“对象.方法”或“对象.属性”赋值
拓展:JavaBean&&UML
⒈JavaBean是一种Java语言写成的可重用组件
⒉所谓JavaBean是指符合如下标准的Java类:
①类是公共的
②有一个无参的公共的构造器
③有属性,且有对应的get,set方法
9关键字:this
this可以用来修饰属性、方法和构造器
this修饰属性和方法
this理解为:当前对象或当前正在创建的对象(构造器)
在类的方法(构造器)中,我们可以用“ this.属性 ”或“ this.方法 ”调用当前(正在创建的)对象的属性或方法。但是,通常情况下,都选择省略“ this ”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“ this.变量 ”的方式,表明此变量是属性,而非形参。
this调用构造器
①我们在类的构造器中,能够显式的使用" this(形参列表) ”方式,调用本类中指定的其他构造器
②构造器中不能通过调用" this(形参列表) ”方式自己
③如果一个类中有n个构造器,则最多有n-1构造器使用了" this(形参列表) ”
④规定:" this(形参列表) ”必须声明在当前构造器的首行
⑤构造器内部最多只能声明一个" this(形参列表) ”,用来调用其他的构造器
对属性进行限制(比如腿的个数不能为负)
public class Restrict {
public static void main(String[] args) {
// TODO Auto-generated method stub
Animal a = new Animal();
}
}
class Animal{
//属性
private String name;
private int leg;
//构造器
public Animal(){
//Animal初始化时,需考虑如下的1、2、3、4...(共40行代码)
}
public Animal(String name){
//Animal初始化时,需考虑如下的1、2、3、4...(共40行代码)
this();//调用构造器,来避免冗杂重复40行代码的问题
this.name = name;
this.setname();
}
public Animal(int leg,String name){
//Animal初始化时,需考虑如下的1、2、3、4...(共40行代码)
this(name);//调用构造器
}
//方法
public void setleg(int leg) {
this.leg = leg;
}
public int Getleg(){
return this.leg;
}
public void setname(String name){
this.name = name;
}
//Source->Generate Getters and Setters
}
10关键字:package、import
package
①为了更好的实现项目中类的管理,提供包的概念
②使用package声明类或接口所属的包
③包,属于标识符,遵循标识符的命名规则
④每“ . ”一次,就代表一层文件目录
⑤同一个包下,不能命名同名的接口、类;不同的包下,可以命名同名的接口、类
import (导入)
1.在源文件中显式的使用import结构导入指定包下的类,接口
2.声明在包的声明和类的声明之间
3.如果需要导入多个结构,则并列写出即可
4.可以使用“ xxx.* ”的方式,表示可以导入xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显式表示
5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6.如果使用的类或接口是本包下定义的,则可以省略import结构
7.如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显式
8.import static: 导入指定类或接口中的静态结构(属性或方法)
import java.util.*;
import com.atguigu.exer4.Account;
//全类名的方式显式
com.atguigu.exer3.Account acct = new com.atguigu.exer3.Account(1000,200,0.12);
import static:java.lang.System.*;
import static:java.lang.Math.*;
out.println("hello");//out:属性
long num = round(123.456);//round:方法
11OOP特征二:继承性(extends)
好处
减少了代码的冗余
便于功能的扩展
为之后的多态性的使用,提供了前提
格式
class A extends B{ }
A:子类(派生类)subclassB:父类(基类)superclass
体现
①一旦子类A继承父类B之后,子类A就获取到了父类B中声明的所有电脑属性和方法
②私有的属性或方法也可以继承,但由于封装性的影响,需要通过方法来获取,不能直接调用
③子类继承父类之后,还可以定义自己特有的属性或方法、
④java只支持单继承和多层继承
⑤如果我们没有显示的声明一个类的父类的话,则次类继承与java.lang.Object类,所有的java类(除java.lang.Object类)都直接或间接的继承于java.lang.Object类
class Person{
String name;
int age;
public Person() {
}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("eat");
}
public void sleep() {
System.out.print("sleep");
}
}
class Student extends Person{
// String name;
// int age;
String major;
//构造器不能继承,省略
public Student() {
}
public Student(String name,int age,String major) {
this.name = name;
this.age = age;
this.major = major;
}
// public void eat() {
// System.out.println("eat");
// }
// public void sleep() {
// System.out.print("sleep");
// }
}
12方法的重写(override)
定义
在子类中可以根据需要从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法覆盖父类的方法
要求
方法的声明:权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型{ };
约定俗成:子类中的叫重写的方法,父类中叫被重写的方法
①子类重写的方法的方法名和形参列表与被重写的方法的方法名和形参列表相同
②子类重写的方法的权限修饰符可以比被重写的方法的权限修饰符更大
>特殊情况:子类不能重写父类中声明为private权限的方法
③返回值类型
>父类被重写的方法的返回值类型是void,则子类中的返回值类型只能是void
>父类被重写的方法的返回值类型是A类型,则子类中的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型,则子类中的返回值类型必须是相同的基本数据类型
④子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
13四种访问权限修饰符
(见封装与隐藏)
14关键字:super(父类的)
super可以用来调用:属性,方法,构造器
调用属性和方法
①可以在子类的方法或构造器中,通过使用“super.属性”或“super.方法”的方式,显式的调用父类中声明的属性或方法。但是,在通常情况下,都习惯省略“super”。
②特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用“super.属性”的方式,表明调用的是父类中声明的属性。
③特殊情况:当子类重写了父类中的方法后,我们想在子类中调用父类中被重写的方法时,则必须显式的使用“super.方法”的方式,表明调用的是父类中被重写的方法。
调用构造器
①可以在子类的构造器中显式的使用“ super(形参列表)”的方式,表示调用父类声明的指定的构造器
②“ super(形参列表)”的使用必须声明在子类构造器的首行
③在一个类的构造器中,针对于this(形参列表)或super(形参列表)只能二选一
④在构造器的首行没有显示的声明this(形参列表)或super(形参列表),则默认调用的是“ super()”
⑤在类的多个构造器中,至少有一个类的构造器中使用了“ super(形参列表)”
15子类对象实例化过程
从结果上看(继承性)
子类继承父类以后,就获得了父类中声明的属性或方法
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
从过程上看
我们通过子类的构造器创建子类对象是,我们一定会直接或间接的调用其父类的构造器,进而调用父类的构造器。直到调用到了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
16OOP特征三:多态性
(一个事物的多种形态)
对象的多态性
父类的引用指向子类的对象/子类的对象赋给父类的引用(可以直接应用在抽象类和接口上)***相当于用一个更大的范围去形容一个更具体的对象(子类特有的方法不能调用)
Person p = new Man();
//其中Person是父类,Man是子类
p.eat();//调用的是子类重写父类的方法
//p是子类的对象,是父类的类型
多态的使用
当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用
虚拟方法的调用(动态绑定):子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法。父类根据赋给它的不同的子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
有了对象的多态性后,内存中实际是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,我们在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法(编译,看左边;运行,看右边)
如何才能调用子类中特有的属性和方法
使用强制类型转换符(向下转型)
Person p2 = new Man();
Man m1 = (Man)p2;
使用情景:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行强制类型转换
instanceof操作符
判断对象a是否是类A的实例。是,返回true。
如果a instanceof A返回true,则a instanceof B也返回true,其中B是A的父类
多态性的使用前提
类的继承关系
要有方法的重写
为什么要有多态性:避免代码的冗余
对象的多态性只适用于方法,不适用于属性(属性不存在多态性)
public class DuoTaiXin {
public static void main(String[] args) {
// TODO Auto-generated method stub
func(new Dog());
func(new Cat());
}
public static void func(Animal1 animal) {
animal.eat();
animal.walk();
}
// public static void func(Dog dog) {
// dog.eat();
// dog.walk();
// }
// public static void func(Cat cat) {
// cat.eat();
// cat.walk();
// }
}
class Animal1{
public void eat() {
System.out.println("吃饭");
}
public void walk() {
System.out.println("叫");
}
}
class Dog extends Animal1{
public void eat() {
System.out.println("吃骨头");
}
public void walk() {
System.out.println("汪汪汪");
}
}
class Cat extends Animal1{
public void eat() {
System.out.println("吃鱼");
}
public void walk() {
System.out.println("喵喵喵");
}
}
17Object类的使用
1.Object是所有类的根父类(数组也作为Object类的子类出现,可以调用Object类中的方法)
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
3.Object类的功能(属性,方法)具有通用性
功能(equals/toString)
1.equals() / toString() / getClass() / hashCode() / clone():复制一个对象
㈠==和equals的区别
①==:可以使用在基本数据类型和引用数据类型变量中
1.如果比较的是基本数据类型,比较两个变量保存的数据是否相等(不一定类型要相等)
2.如果比较的是引用数据类型,比较两个对象的地址值是否相等
int i = 10;
int j = 10;
double k = 10.0;
System.out.println(i==j);//true
System.out.println(i==k);//true
// boolean w = true;
// System.out.println(i==w);
char c = 10;
System.out.println(i==c);//true
char c1 = 65;
char c2 = 'A';
System.out.println(c1==c2);//true
②equals:是一个方法,而非运算符,只适用于引用数据类型
1.Object类中equals()的定义:
public boolean equals(Object obj){
return (this==obj);
}//说明:Object类中定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个个体
2.重写Object的equals:
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相等。那么,我们就需要对Object类中的equals()进行重写。
3.String类中equals()即为比较内容是否相同
String str1 = new String("aaaa");
String str2 = new String("aaaa");
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2));//true
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2));//false
㈡ toString
1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()方法
2.Object类中toString的定义:
public String toString() {
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}//说明:Object中toString()方法与System.out.println(atr)一样输出地址值
3.在String、Date、File、包装类等都重写了Object类中的toSting()方法
4.重写toString
18包装类的使用
针对八种基本数据类型定义相应的引用数据类型--包装类
基本数据类型与、包装类与String类间的转换
自动装箱/自动拆箱
int num = 10;
Integer in1 = num;//自动装箱
int num1 = in;//自动拆箱
基本数据类型,包装类---->String
int num = 10;
//方式一:连接运算
String Str1 = num+" ";
//方式二:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
String---->基本数据类型,包装类
String str1 = "123";
//调用包装类的parseXxx(String s)
int num = Integer.parseInt(str1);
Syso(num+1);
String str2 = "true";
boolean b = Boolean.parseBoolean(str2);//可能会爆NumberFormatException
鬼题
//1.
Object o1 = true?new Integer(1):new Double(2.0);
System.out.println(o1);//1.0 三目运算符自动提升类型
//2.
Object o2;
if(true)
Integer(1);
else
Double(2.0);//1
//3.
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j);//false
//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128到127范围内的整数,如果我们使用自动装箱的方式,给Integer赋值的范围在-128到127范围内是,可以直接使用数组中的元素
Integer m = 1;
Integer n = 1;
syst.out.println(m==n);//true
Integer x = 128;//想当于new了一个对象
Integer y = 128;
System.out.println(x==y);//false
详解:https://zhuanlan.zhihu.com/p/538300264
详解:http://"C:\Users\姜九笙\eclipse-workspace\hello\src\Exercise5\ScoreTest.java"
关于可以直接将Object o1 = true:
java中Object o1=true为什么是正确的?_百度知道
https://blog.csdn.net/weter_drop/article/details/105179308
19关键字:static
1.static:静态的
2.static可以用来修饰:属性、方法、代码块、内部类
static修饰属性: 静态变量
1.属性按是否使用static修饰又分为:静态属性(类变量)vs非静态属性(实例变量)
①实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性时,不会导致其他对象中同样的属性值的修改。
②静态变量:我们创建了类的多个对象,多个对象共享一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用次静态变量时,是修改过的。
③其他说明:静态变量随着类的加载而加载
静态变量的加载要早于对象的创建
由于类只加载一次,则静态变量在内存中也只会存在一份,存在方法的静态域中
可调用的 | 类变量/静态方法 | 实例变量/非静态方法 |
---|---|---|
类 | yes | no |
对象 | yes | yes |
static修饰方法:静态方法
1.随着类的加载而加载,可以通过“ 类.静态方法 ”的方式进行调用
2.静态方法中,只能调用静态的方法或属性。
非静态方法中,既可以调用非静态方法或属性,也可以调用静态方法或属性。
3.在静态的方法中,不能使用this/super关键字
4.关于静态属性和静态方法的使用。从生命周期的角度去理解
*在开发中,如何确定一个属性是否要声明为static的?
>属性可以被多个对象所共享的,不会随着对象的不同而不同
>类中的常量也常常声明为static
*在开发中,如何确定一个方法是否要声明为static的?
>操作静态属性的方法,通常设置为static
>工具类中的方法,习惯上声明为static的。比如:Math,Arrays,collections
单例设计模式
饿汉式vs懒汉式
饿汉式:坏处:对象加载时间过长。好处:是线程安全的
懒汉式:好处:延迟对象的创建。坏处:线程不安全-->到多线程时,再修改
20理解main方法的语法
main()方法的使用:
1.main()方法作为程序的入口
2.main()方法也是一个普通的静态方法
3.main()方法可以作为我们与控制台交互的方式
21类的成员之四:代码块
代码块的作用
用来初始化类,对象
代码块如果有修饰的话,只能用static。因此分为静态代码块和非静态代码块
静态代码块vs非静态代码块
静态代码块
>可以有输出语句
>随着类的加载而执行,而且只执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行优先于非静态代码块的执行
>只能调用静态的属性,方法,不可以调用非静态的
非静态代码块
>可以有输出语句
>随着对象的加载而执行
>每创建一个对象,就执行一次
>作用:可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>可以调用静态的,非静态的属性和方法
static{
}
{
}
代码块,构造器执行顺序问题
静态代码块优于非静态代码块优于构造器
父类先于子类,静态先于非静态,代码块先于构造器
(构造器:创建对象过程中,等非静态代码块初始化结束,才执行构造器的主题代码
非静态代码块:在创建对象的同时执行)
静态代码块只在第一次new的时候执行,之后再创建对象也不会执行,但是非静态代码块在每次创建对象的时候都会执行一次
属性赋值的先后问题
默认初始化-显式初始化/在代码块中赋值-构造器中初始化- 通过对象初始化
22关键字:final
final(最终的):可以修饰类、方法、变量
final修饰类
此类不能被其他类继承 (例如:String类,System类...)
final class Finala{
}
fianl修饰方法
该方法不能再被重写 (例如:Object类中的getclass();
public final void show(){
}
final修饰变量
此时的变量就称为常量
1.final修饰属性
可以考虑的位置有:显式初始化、代码块中初始化、构造器中初始化
//显式初始化
final int NUM = 0;
//代码块中初始化
final int LEFT;
{
LEFT=10;
}
//构造器中初始化
public FinalTest(){
LEFT =1;
}
2.final修饰局部变量
尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参以后,就只能在方法体内使用此形参,不能改变其值
public void show(){
final int NUM=10;
}
public void show(final int num){
}
static final:用来修饰属性,全局常量
static final+属性:全局常量
final修饰对象Java中Final修饰对象 - 百度文库
23抽象类与抽象方法(abstract)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计,应该保证父类和子类能够共享特征,有时将一个父类设计的非常抽象,以至于他没有具体的实例,这样的类叫做抽象类。
abstract可以用来修饰:类,方法
abstract修饰类(抽象类)
>此类不能实例化
>抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
>开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作
abstract修饰方法(抽象方法)
>抽象方法只有方法的声明,没有方法体。
>包含抽象方法的类一定是个抽象类;反之,抽象类中可以没有抽象
方法。
` >若子类重写的父类中的所有的抽象方法,则此子类方可实例化;若子类没有重写父类中的所有抽象方法,则此子类也是一个抽象类,需要用abstract修饰。
abstract使用的注意点
、 >abstract不能用来修饰属性,构造器等
>abstract不能用来修饰私有方法(不能重写),静态方法(不叫重写),final的方法(不能重写)
abstract class Person{
public abstract void eat();
}
抽象类的匿名子类
Worker worker = new Worker();
method(worker);//非匿名的类非匿名的对象
method(new Worker());//非匿名的类匿名的对象
//创建了一匿名子类的对象:p
Person2 p = new Person2() {
@Override
public void eat() {
System.out.println("eat");
}
};
method(p);
//创建匿名子类的匿名对象
method(new Person2() {
@Override
public void eat() {
System.out.println("eat.");
}
});
}
public static void method(Person2 p) {
p.eat();
}
}
abstract class Person2{
public abstract void eat();
}
class Worker extends Person2{
@Override
public void eat() {
}
}
模板方法设计模式
见hello的TemplateTest,****Exercise8*****
24接口(interfere)
概述
使用
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:JDK7以前,只能定义全局常量和抽象方法
JDK8,除了定义全局常量和抽象方法之外,还可以定义静态方法,默认方法
4.接口中不可以定义构造器,意味着接口不能实例化
5.Java开发中,接口通过让类去实现(implements)的方式来使用,如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化...
6.Java类可以实现多个接口--->弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD{ }
7.接口与接口之间可以继承,而且可以多继承
8.接口的具体使用,体现多态性
9.接口,实际上可以看做是一种规范
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;//宇宙第一速度
int MIN_SPEED = 1;//书写时可以省略public static final
//抽象方法
public abstract void fly();
void stop();//省略public abstract
// Interfaces cannot have constructors,不能创建构造器
// public Flyable(){
//
// }
}
interface Attackable{
void attack();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("通过引擎起飞");
}
@Override
public void stop() {
System.out.println("停");
}
}
class BUllet extends Plane implements Flyable,Attackable,CC{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
@Override
public void method1() {
}
@Override
public void method2() {
}
}
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
public class USBTest {
public static void main(String[] args) {
Computer computer = new Computer();
USB flash = new Flash();//多态
computer.transfereData(flash);
}
}
class Computer{
public void transfereData(USB usb) {//多态的体现
usb.start();
System.out.println("具体传输数据");
usb.end();
}
}
interface USB{
void start();
void end();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘已启动");
}
@Override
public void end() {
System.out.println("U盘已安全弹出");
}
}
Computer computer = new Computer();
//创建了接口非匿名实现类的的非匿名对象
Flash flash = new Flash();
computer.transfereData(flash);
//创建了接口的非匿名实现类的匿名对象
computer.transfereData(new Printer());
//创建了接口的匿名实现类的非匿名对象
USB phone = new USB() {
@Override
public void start() {
System.out.println("手机已启动");
}
@Override
public void end() {
System.out.println("手机已关机");
}
};
computer.transfereData(phone);
//创建了接口的匿名实现类的匿名对象
computer.transfereData(new USB() {
@Override
public void start() {
System.out.println("音响已启动");
}
@Override
public void end() {
System.out.println("音响已关机");
}
});
代理模式:见NetWork.java
练习:Exercise9
JDK8中接口可以定义静态方法,默认方法
1.接口中中定义的静态方法,只能通过接口来调用。
2.通过实现类的对象,可以调用接口中的默认方法 。
3. 类优先原则--->如果子类(实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法。
4.接口冲突--->如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法 ,那么在实现类没有重写此方法的情况下,报错。这就需要我们必须重写此方法。
5.如何在子类中调用父类或接口中被重写的方法
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
CompareA.super.method3();//调用接口中的默认方法
//JDK8中可以定义静态方法,默认方法
interface CompareA{
//静态方法
public static void method1() {
System.out.println("CompareA.北京");
}
//默认方法
public default void method2() {
System.out.println("CompareA.上海");
}
default void method3() {
System.out.println("CompareA.成都");
}
}
interface CompareB{
public default void method3() {
System.out.println("CompareB.成都");
}
}
class Superclass{
public void method3() {
System.out.println("super.成都");
}
}
class Subclass extends Superclass implements CompareA,CompareB{
public void method2() {//重写
System.out.println("重写.上海");
}
public void method3() {
System.out.println("重写.成都");
}
public void mymethod() {
// 知识点5.如何在子类中调用父类或接口中被重写的方法
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
CompareA.super.method3();//调用接口中的默认方法
CompareB.super.method3();
}
}
class SubclassTest{
public static void main(String[] args) {
Subclass s = new Subclass();
// s.method1();
// 知识点1.接口中中定义的静态方法,只能通过接口来调用
// Subclass.method1();
CompareA.method1();
// 知识点2.通过实现类的对象,可以调用接口中的默认方法
s.method2();
// 知识点3.类优先原则--->
// 如果子类(实现类)继承的父类和实现的接口中声明了同名同参数的方法,
// 那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法
s.method3();
// 知识点4.接口冲突--->
// 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法 ,
// 那么在实现类没有重写此方法的情况下,报错。
// 这就需要我们必须重写此方法。
s.method3();
}
}
25类的成员之五:内部类
概念
成员内部类
一方面,作为外部类的成员
>调用外部类的结构(静态不能调用非静态...)
>可以用static修饰
>可以使用四种权限修饰符修饰
另一方面,作为一个类
>类中可以定义属性,方法,构造器等
>可以用final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承。
>可以被abstract修饰
关注如下三个问题
1.如何实例化成员内部类的对象
//创建Innerclass1的实例(静态成员内部类)
Exclass.Innerclass1 in1 = new Exclass.Innerclass1();
in1.method1();
//创建Innerclass2的实例(非静态成员内部类)
Exclass ex2 = new Exclass();
Exclass.Innerclass2 in2 = ex2.new Innerclass2();
in2.method2();
2.如何在成员内部类中区分调用外部类的结构
class Exclass{
String name;
int age;
class Innerclass2{
String name;
public void method2()
Exclass.this.method3();//调用外部类的方法
System.out.println(age);
public void display(String name)
{
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Exclass.this.name);//外部类的属性
}
}
}
3.开发中局部内部类的使用(InnerclassTest)
public class InnerclassTest1 {
// 开发中很少见
public void method() {
class AA{
}
}
// 返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {//Comparable:要返回的类型
//创建一个实现了Comparable接口的类:局部内部类
//方法一:创建了一个有名实现类的匿名对象
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// // TODO Auto-generated method stub
// return 0;
// }
// }
// return new MyComparable();
//方法二:创建了一个匿名实现类的匿名对象
return new Comparable() {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
}
}
END
异常处理
1异常概述与异常体系结构
Error
public static void main(String[] args) {
// 1.栈溢出:java.lang.Stack OverflowOverflowError
main(args);
// 2.堆溢出:java.lang.OutOfMemoryError
Integer[] arr = new Integer[1024*1024*1024];
}
Exception
2常见异常
public class ExceptionTest {
// 运行时异常
// (1)空指针异常:java.lang.NullPointerException
@Test
public void test1() {
int[] arr = null;
System.out.println(arr[3]);
String str = "abc";
//System.out.println(str.charAt(0));//✔
str = null;
System.out.println(str.charAt(0));//✘
}
// (2)数组下标越界:java.lang.ArrayIndexOutOfBoundsException
@Test
public void test2() {
int[] arr = new int[3];
System.out.println(arr[3]);
// StringIndexOutOfBoundsException
String str = "abc";
System.out.println(str.charAt(3));
}
// (3)类型转换异常:java.lang.ClassCastException
@Test
public void test3() {
//String str = new Date();//不算该类型
Object obj = new Date();
String str = (String)obj;
}
// (4)数字格式化异常:java.lang.NumberFormatException
@Test
public void test4() {
String str = "123";//✔
str = "abc";//✘
int num = Integer.parseInt(str);
}
// (5)接收非法输入异常:java.util.InputMismatchException
@Test
public void test5() {
Scanner in = new Scanner(System.in);
int score = in.nextInt();//输入的时候不是数字出错
System.out.println(score);
in.close();
}
// (6)算术异常:java.lang.ArithmeticException
@Test
public void test6() {
int a = 10;
int b = 0;
System.out.println(a/b);//1.除0
}
// *******************************
// 编译时异常
// (1)
@Test
public void test7() {
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data!=-1)
{
System.out.println((char)data);
data = fis.read();
fis.close();
}
}
}
3异常处理机制一:try-catch-finally
抓抛模型
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。并将此对象抛出。
一旦抛出对象以后,其后的代码就不再执行。
关于异常对象的产生:1.系统自动生成的异常对象
2.手动的生成一个异常对象,并抛出(throw)
过程二:“抓” :可以理解我异常的处理方式:1.try-catch-finally 2.throws
try{
//可能出现异常的代码
} catch(异常类型1 变量名1){
//处理异常的方式1
}
catch(异常类型2 变量名2){
//处理异常的方式2
}
......
finally{
//一定会执行的代码
}
注意事项
1.finally是可选的。
2.使用try将可能出现的异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常的对象,根据此对象的类型,去catch中匹配。
3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理完成,就跳出当前的try-catch结构(无finally情况),继续执行其后的代码。
4.catch中的异常类型如果没有子父类关系,则谁声明在下无所谓。catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面,否则会报错。
5.常用异常处理方式:1.String getMessage();
2.printStackTrace();
6.在try结构中声明的变量,再出了try之后,就不能在调用。
7.体会:使用try-catch-finally解决编译时异常,使得程序在编译时不再报错,但是运行时扔可能报错,相当于我们使用try-catch-finally讲一个编译时可能出现的异常,延迟到运行时出现。
开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
finally
8.finally中声明的是一定会被执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
9.什么时候用finally:像数据库连接,输入输出流,网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动的进行资源的释放,此时的资源释放,就需要声明在finally中。
10.try-catch-finally结构是可以嵌套·的
代码见ExceptionTest
4异常处理机制二:throws
格式
1.throws + 异常类型 写在方法的声明处,指明此方法执行时,可能会抛出的异常类
型。
2. 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码就不再执行。
体会
try-catch-finally才是真正的将异常处理掉了;
throws只是将异常抛给了方法的调用者,并没有真正的将异常处理掉。
public class ExceptionTest2 {
public static void main(String[] args) {
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2() throws IOException{
method1();
}
public static void method1()throws FileNotFoundException,IOException {
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data!=-1)
{
System.out.println((char)data);
data = fis.read();
fis.close();
}
}
}
ExceptionTest2
方法重写规则之一
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
public class OverrideTest {
public static void main(String[] args) {
display(new Subclass1());
}
public static void display(Superclass1 s){
try {
s.method();
} catch (IOException e) {//如果子类的方法抛出的异常值大于父类,在传入此方法时这就报错
e.printStackTrace();
}
}
}
class Superclass1{
public void method() throws IOException{
}
}
class Subclass1 extends Superclass1{
public void method1() throws FileNotFoundException{
}
}
OverrideTest
开发中如何选择使用try-catch-finally 还是使用throws?
1.如果父类中被重写 的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。
2.在执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的,建议这几个方法使用throws的方式进行处理,而执行的方法a可以考虑使用try-catch-finally方式进行处理
5手动抛出异常:throw
public class ThrowTest {
public static void main(String[] args) {
Stu s = new Stu();
try {
s.regist(-1001);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(s);
}
}
class Stu{
private int id;
public void regist(int id) throws Exception {
if(id>0)
this.id = id;
else
// System.out.println("您输入的数据非法!");
// 1.手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// 2.运行时才能检测
// throw new Exception();
// 3.自定义异常类
throw new MyException("输入不能为负数");
}
}
ThrowTest
6用户自定义异常类
如何自定义异常类
1.继承于现有的异常结构:RuntimeException、Exception
2.提供全局常量:serialVersionUID
3.提供重载的构造器
/*
* 如何自定义异常类
* 1.继承于现有的异常结构:RuntimeException、Exception
* 2.提供全局常量:serialVersionUID
* 3.提供重载的构造器
*/
public class MyException extends RuntimeException{
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
}
public MyException(String msg){
super(msg);
}
}
MyException
Exercise9_10毁灭吧
多线程
1.基本概念:程序,进程,线程
概念
单核CPU和多核CPU
使用多线程的优点
解释:单核只能并发执行多线程(切换开销),没法并行执行多线程,所以导致做一个事情用2个线程比用一个线程时间更多
何时需要多线程
2.线程的创建与使用
Thread类中有关方法
代码见ThreadMethodTest
/*
测试Thread中常用方法:
1.start():启动当前线程,调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前CPU的执行权
7.join():在线程a中调用线程b的join(),此时线程啊就进入阻塞状态,直到线程b执行完以后,线程a才结束阻塞状态
8.stop():强制结束当前方法(已过时)
9.sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒,在指定的millitime毫秒时间内,当前线程时阻塞状态
10.isAlive():判断线程还是否存在
*/
public class ThreadMethodTest {
public static void main(String[] args) {
HelloThread helloThread = new HelloThread("Thread_1");
helloThread.start();
// setName方式一: helloThread.setName("线程一");
// 给主线程命名
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if (i % 2 == 0)
System.out.println(Thread.currentThread().getName() + ":" + i);
if (i == 20) {
try {
helloThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(helloThread.isAlive());
}
}
class HelloThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
try {
sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
if (i % 20 == 0)
this.yield();
}
}
// setName方式二:
public HelloThread(String name) {
super(name);
}
}
多线程的创建
方式一:继承于Thread类
1.创建一个继承于Thread类的子类
2.重写Thread的run()方法
3.创建Thread类的子类的对象
4.通过此对象调用start()方法:
作用: 1.启动当前线程
2.调用当前线程的run()方法
注意:
代码见ThreadTest和ThreadDemo
方式二:实现Runnable接口
1.创建一个实现了Runnable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()
作用:1.启动线程
2.调用当前线程的run()--->调用了Runna类型的target的run()
代码见ThreadTest2
区分这两种方法的代码:ThreadWindowsTest1和ThreadWindowsTest2
创建线程的两种方式的比较
开发中,优先选择实现Runnable接口的方式
原因: 实现的方式没有类的单继承性的局限性
实现的方式更适合来处理多个线程有共享数据的情况
联系:public class Thread implements Runnable。
相同点: 两种方式都需要去重写run(),将线程要执行的逻辑声明在run()中。
线程的调度
代码见ThreadMethodTest
3.线程的生命周期
4.线程的同步
"C:\Users\姜九笙\Desktop\新建文件夹\1_课件\第2部分:Java高级编程\第2部分:Java高级编程\尚硅谷_宋红康_第8章_多线程\尚硅谷_宋红康_第8章_多线程.pdf"
代码笔记见ThreadWindowsTest1(同步代码块解决继承Thread类的线程安全问题)
ThreadWindowsTest2(同步代码块解决实现Runnable接口的线程安全问题)(主)
ThreadWindowsTest3(同步方法解决继承Thread类的线程安全问题)
ThreadWindowsTest4(同步方法解决实现Runnable接口的线程安全问题)
LockTest(Lock锁解决线程安全问题),LanHan,DeadlockTest
5.线程的通信
代码笔记见ThreadCommunicationTest(主)
wait(),notify(),notifyAll()
ThreadComCustomerTest(练习,经典)
6.JDK5.0新增线程创建方法
ThreadCallableTest(实现Callable接口)
ThreadPoolTest(线程池)
集合
1Java集合框架概述
2Collection接口方法
3Iterator迭代器接口
4Collection子接口一:List
5Collection子接口二:Set
6Map接口
7Collections工具类
常用类 (详见PPT)
1 字符串相关的类
String类
String的常用方法
String与其他类进行转换
StringBuffer
StringBuilder
2JDK8之前的日期时间API
System静态方法
Date类
Calendar类
SimpleDateFormat类
3JDK8中日期时间API
LocalDate,LocalTime,LocalDateTime
Instant
DateTimeFormatter
其他类
4Java比较器
Comparable接口
Comparator接口
5System类
6Math类
7BigInteger与BigDecimal