第二章 java基础语法
快捷键:
alt+enter 导包
ctrl+alt+f 截屏
psvm sout
一、JAVA起源和演变
1、90年代单片式计算机诞生
2、SUN 1991成立“Green"项目小组
3、开始向使用C++,后开发叫"Oak"的面向对象语言
4、后更名JAVA
二、JAVA体系与特点
Java SE:java Platform Standard Edition
标准版:各应用平台基础,桌面开发和低端商务应用的解决方案。
JavaEE:java platform enterprise edition
企业版:以企业为环境而开发应用程序的的解决方案。
javaME:Javaplatform Micro Edition
微型版:致力于消费产品和嵌入式设备。
三、JAVA特性:
1、纯面向对象编程语言。
2、跨平台
3、健壮性(吸收C/C++优点,没有C++的指针更安全的操作存储空间同时又有面向对象机制和垃圾回收机制)
4、安全性
四、java两种核心机制
1、JVM
2、GC(Garbage Collection)
1)不再使用的内存空间y应当进行回收
2)在C/C++中由程序员负责回收无用内存
3)java语言消除了程序员回收无用空间的责任
4)JVM提供了一个系统线程,用于跟踪存储空间分配情况,检查并释放哪些可以被释放的存储空间
5)垃圾回收器在java程序运行过程中自动启用,程序员无法精确控制和干预。
五、JDK JRE
1、JDK:java development kit
JRE javaAPI JVM
2、JRE:java runtime environment
JVM
六、JDK11安装
1、java被oracle收购,
2、进入www.oracle.com
3、下载jdk11安装包
4、安装
5、将jdk下的bin目录加入环境变量的path中
或者使用JAVA_HOME
1、在环境变量中加JAVA_HOME
2、设置值为jdk11我文件夹路径
3、在path中添加:%JAVA_HOME%\bin
七、eclipse安装
1、进入官网:http://eclipse.org/
2、点击download packages
3、选第一个
4、将eclipse解压即可
八、判断用户输入类型
Scanner input=new Scanner(System.in);
if(input.hasNextInt()){
int num=input.nextInt();
}
九、命名规范
1、标识符
由字母、数字、下划线(_)和美元符号($)组成。新职课-教研教学中心
不能以数字开头。
区分大小。
长度无限制。
不能是 Java 中的保留关键字。
2、
类名规范:XxxYyyZzz 首字母大写,后面每个单词首字母大写(大驼峰式)。
方法名规范:xxxYyyZzz 首字母小写,后面每个单词首字母大写(小驼峰式)。
变量名规范:xxxyyyzzz 全部小写。
第三章 面向对象
一、阿里巴巴编程规范
1、阿里巴巴编程规范:
链接:https://pan.baidu.com/s/1cIt2TCfLmWehh-xQe42ZfQ
提取码:tbrm
二、代码块
2、代码块
1)普通代码块:在方法或语句中出现的{}就称为普通代码块
public class CodeBlock01{
public static void main(String[] args){
{
int x=3;
System.out.println("1,普通代码块内的变量x="+x);
}
int x=1;
System.out.println("主方法内的变量x="+x);
{
int y=7;
System.out.println("2,普通代码块内的变量y="+y);
}
}
}
2)构造代码块:在类中的成员代码块 每次对象创建时执行 执行在构造方法之前
直接在类中定义且没有加static关键字的代码块称为{}构造代码块
public class CodeBlock02{
{
System.out.println("第一代码块");
}
public CodeBlock02(){
System.out.println("构造方法");
}
{
System.out.println("第二构造块");
}
public static void main(String[] args){
new CodeBlock02();
new CodeBlock02();
new CodeBlock02();
}
}
执行结果:
第一代码块
第二构造块
构造方法
第一代码块
第二构造块
构造方法
第一代码块
第二构造块
构造方法
3)静态代码块:
(1)在类中使用static修饰的成员代码块 在类加载时执行 程序启动到关闭只会执行一次的代码块
(2)在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。
(3)如果类中包含多个静态代码块,那么将按照"先定义的代码先执行,后定义的代码后执行"
(4)静态代码块不能存在于任何方法体内
(5)静态代码块不能直接访问静态实例变量和实例方法,需要通过类的实例对象来访问
class Code{
{
System.out.println("Code的构造块");
}
static{
System.out.println("Code的静态代码块");
}
public Code(){
System.out.println("Code的构造方法");
}
}
public class CodeBlock03{
{
System.out.println("CodeBlock03的构造块");
}
static{
System.out.println("CodeBlock03的静态代码块");
}
public CodeBlock03(){
System.out.println("CodeBlock03的构造方法");
}
public static void main(String[] args){
System.out.println("CodeBlock03的主方法");
new Code();
new Code();
new CodeBlock03();
new CodeBlock03();
}
}
运行结果:
CodeBlock03的静态代码块
CodeBlock03的主方法
Code的静态代码块
Code的构造块
Code的构造方法
Code的构造块
Code的构造方法
CodeBlock03的构造块
CodeBlock03的构造方法
CodeBlock03的构造块
CodeBlock03的构造方法
4)同步代码块
面试题:
静态代码块->构造代码块->构造方法
三、super this
3、super、this
1) super(参数):调用基类中的某一个构造函数(应该为构造函数中的第一条语句)
2) this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
3) super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
4) this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
5) 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
6) super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
7) super()和this()均需放在构造方法内第一行。
8) 尽管可以用this调用一个构造器,但却不能调用两个。
9) this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
10) this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
11) 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
四、final
4、final
1)修饰类
i、表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法
ii、在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类
2)修饰方法
i、只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。即父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。
ii、final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法。)
3)修饰变量
i、final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
ii、当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
iii、final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
iv、当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
五、抽象类、接口
5、抽象类、接口
1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2)抽象类不能用来创建对象;
3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
两者区别:
1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
5)抽象类可以有构造器,接口不能有构造器
6)抽象方法可以有public、protected和default这些修饰符,接口方法默认修饰符是public。你不可以使用其它修饰符。
7)抽象方法可以有main方法并且我们可以运行它,接口没有main方法,因此我们不能运行它。(java8以后接口可以有default和static方法,所以可以运行main方法)
8)它比接口速度要快
9)如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。
六、instanceof
6、instanceof
1)用法:
result = object instanceof class
参数:
Result:布尔类型。
Object:必选项。任意对象表达式。
Class:必选项。任意已定义的对象类。
2)在编译状态中,class可以是object对象的父类,自身类,子类。在这三种情况下Java编译时不会报错。
3)在运行转态中,class可以是object对象的父类,自身类,不能是子类。在前两种情况下result的结果为true,最后一种为false。但是class为子类时编译不会报错。运行结果为false。
七、toString
7、toString
1)toString()方法返回反映这个对象的字符串
2)toString方法是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”
3)System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法
【1】undefined和null没有toString()方法
undefined.toString();//错误
null.toString();//错误
【2】布尔型数据true和false返回对应的'true'和'false
true.toString();//'true'
false.toString();//'false'
【3】字符串类型原值返回
'1'.toString();//'1'
''.toString();//''
'abc'.toString();//'abc'
【4】数值类型的情况较复杂
1、正浮点数及NaN、Infinity加引号返回
1.23.toString();//'1.23'
NaN.toString();//'NaN'
Infinity.toString();//'Infinity'
2、负浮点数或加'+'号的正浮点数直接跟上.toString(),相当于先运行toString()方法,再添加正负号,转换为数字
+1.23.toString();//1.23
typeof +1.23.toString();//'number'
-1.23.toString();//-1.23
typeof -1.23.toString();//'number'
3、整数直接跟上.toString()形式,会报错,提示无效标记,因为整数后的点会被识别为小数点
因此,为了避免以上无效及报错的情况,数字在使用toString()方法时,加括号可解决
(0).toString();//'0'
(-0).toString();//'0'
(+1.2).toString();//'1.2'
(-1.2).toString();//'-1.2'
(NaN).toString();//'NaN'
4、数字类型的toString()方法可以接收表示转换基数(radix)的可选参数,如果不指定此参数,转换规则将是基于十进制。同样,也可以将数字转换为其他进制数(范围在2-36)
var n = 17;
n.toString();//'17'
n.toString(2);//'10001'
n.toString(8);//'21'
n.toString(10);//'17'
n.toString(12);//'15'
n.toString(16);//'11'
八、String StringBuffer StringBuilder
8、String StringBuffer StringBuilder
1)java.lang.String、java.lang.StringBuffer、java.lang.StrungBuilder
2)共同之处:都是final类,不允许被继承
3)区别:
(1)运行速度:StringBuilder > StringBuffer > String
String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:
pubic class test{
public static void main(String[] args){
String str="abc";
System.out.println(str);
str=str+"de";
System.out.println(str);
}
}
运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
(2)安全:
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
九、内部类
10、内部类
1)成员内部类
成员内部类也是最普通的内部类,它是外围类的一个成员,可以无限制访问外围类的所有成员属性和方法,尽管是private的。
外围类要访问内部类的成员属性和方法需要通过内部类实例来访问。
注意点:
成员内部类中不能存在任何static的变量和方法
成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
public class OuterClass {
private String str;
public void outerDisplay(){
System.out.println("outerClass...");
}
public class InnerClass{
public void innerDisplay(){
//使用外围内的属性
str = "chenssy...";
System.out.println(str);
//使用外围内的方法
outerDisplay();
}
}
/*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
--------------------
chenssy...
outerClass...
2)局部内部类
嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
public class Parcel5 {
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
3)匿名内部类
button2.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("你按了按钮二");
}
});
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}
----------------
Output:
5
注意点:
1、 匿名内部类是没有访问修饰符的。
2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
4)静态内部类
使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
1、 它的创建是不需要依赖于外围类的。
2、 它不能使用任何外围类的非static成员变量和方法。
public class OuterClass {
private String sex;
public static String name = "chenssy";
/**
*静态内部类
*/
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _name1 = "chenssy_static";
public void display(){
/*
* 静态内部类只能访问外围类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + name);
}
}
/**
* 非静态内部类
*/
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _name2 = "chenssy_inner";
/* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + name);
}
}
/**
* @desc 外围类方法
* @author chenssy
* @data 2013-10-25
* @return void
*/
public void display(){
/* 外围类访问静态内部类:内部类. */
System.out.println(InnerClass1._name1);
/* 静态内部类 可以直接创建实例不需要依赖于外围类 */
new InnerClass1().display();
/* 非静态内部的创建需要依赖于外围类 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 方位非静态内部类的成员需要使用非静态内部类的实例 */
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
----------------
Output:
chenssy_static
OutClass name :chenssy
chenssy_inner
OuterClass name:chenssy
十、包装类
11、包装类
1)所有包装类都可以将与之对应的基本数据类型作为参数来创建它们的实例对象
2)除了Character类之外,其他包装类都可以将一个字符串作为参数来构造它们的实例
3)Boolean类的构造方法参数为String类型时,若该字符串为true(不论大小写),则该对象表示true,否则表示false
4)当包装类Number构造方法的参数为String类型时,字符串不能为null,并且该字符串必须能够解析为基本类型的数据
public static void main(String[] args) {
//所有包装类都可以将与之对应的基本数据类型作为参数来创建它们的实例对象
Integer a = new Integer(100);
Double b = new Double(100.00);
Character c = new Character('A');
Boolean d = new Boolean(true);
System.out.println(a+" "+ b+" "+c+" "+d);//100 100.0 A true
//除了Character类之外,其他包装类都可以将一个字符串作为参数来构造它们的实例
Integer a1 = new Integer("100");
Double b1 = new Double("100.00");
Boolean d1 = new Boolean("true");
System.out.println(a1+" "+ b1+" "+d1);//100 100.0 true
/*
* Boolean类的构造方法参数为String类型时:
* 若该字符串为true(不论大小写),则该对象表示true,否则表示false
*/
Boolean d2 = new Boolean("True");
Boolean d3 = new Boolean("TRUE");
Boolean d4 = new Boolean("hello");
System.out.println(d2+" "+d3+" "+d4);//true true false
/*
* 当包装类Number构造方法的参数为String类型时,字符串不能为null
* 并且该字符串必须能够解析为基本类型的数据
* 否则会抛出数字格式异常。
*/
Integer a2 = new Integer("");//NumberFormatException: For input string: ""
Integer a3 = new Integer(null);//NumberFormatException: null
Integer a4 = new Integer("abc");//NumberFormatException: For input string: "abc"
}
5)Integer i = new Integer(100); int in2 = i.intValue();
6)int num1 = Integer.parseInt("100");
7)//将字符串按任意进制转换为int数
int num2 = Integer.parseInt("100", 8);
int num3 = Integer.parseInt("ff", 16);
8) String s1 = Integer.toString(100);
String s2 = Integer.toString(100,8);
String s3 = Integer.toString(100,16);
十一、数组初始化
12、数组初始化
//指定数组大小
int a[] = new int[3];
//数组初始化
int b[] = {1,2,3};
int[] c = {1,2,3};
int[] d = new int[]{1,2,3};
十二、异常
13、IDEAL
1)错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
2)异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。
总体上我们根据Javac对异常的处理要求,将异常类分为2类。
1)非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally)这样的异常,也可以不处理。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
2)检查异常(checked exception):除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。
1)异常处理基本语法
需要注意的地方:
1、try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
try{
//try块中放可能发生异常的代码。
//如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
//如果发生异常,则尝试去匹配catch块。
}catch(SQLException SQLexception){
//每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java7中可以将多个异常声明在一个catch中。
//catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
//在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
//如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
//如果try中没有发生异常,则所有的catch块将被忽略。
}catch(Exception exception){
//...
}finally{
//finally块通常是可选的。
//无论异常是否发生,异常是否匹配被处理,finally都会执行。
//一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
//finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
}
2)throws语法
public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{
//foo内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他们的子类的异常对象。
}
3)finally
1、finally块没有处理异常的能力。处理异常的只能是catch块。
2、在同一try…catch…finally块中 ,如果try中抛出异常,且有匹配的catch块,则先执行catch块,再执行finally块。如果没有catch块匹配,则先执行finally,然后去外面的调用者中寻找合适的catch块。
3、在同一try…catch…finally块中 ,try发生异常,且匹配的catch块中处理异常时也抛出异常,那么后面的finally也会执行:首先执行finally块,然后去外围调用者中寻找合适的catch块。
4)自定义 异常
按照国际惯例,自定义的异常应该总是包含如下的构造函数:
一个无参构造函数
一个带有String参数的构造函数,并传递给父类的构造函数。
一个带有String参数和Throwable参数,并都传递给父类构造函数
一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
public class IOException extends Exception
{
static final long serialVersionUID = 7818375828146090155L;
public IOException()
{
super();
}
public IOException(String message)
{
super(message);
}
public IOException(String message, Throwable cause)
{
super(message, cause);
}
public IOException(Throwable cause)
{
super(cause);
}
}
5)throw
public void setAge(int age){
if(age<0||age>180){
RuntimeException e=new RuntimeException("年龄不符合");
return e;
}
}
5)子类重写父类异常方法注意事项
当子类重写父类的带有 throws声明的函数时,其throws声明的异常必须在父类异常的可控范围内——用于处理父类的throws方法的异常处理器,必须也适用于子类的这个带throws方法 。这是为了支持多态。
在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。
class Father
{
public void start() throws IOException
{
throw new IOException();
}
}
class Son extends Father
{
public void start() throws Exception
{
throw new SQLException();
}
}
/**********************假设上面的代码是允许的(实质是错误的)***********************/
class Test
{
public static void main(String[] args)
{
Father[] objs = new Father[2];
objs[0] = new Father();
objs[1] = new Son();
for(Father obj:objs)
{
//因为Son类抛出的实质是SQLException,而IOException无法处理它。
//那么这里的try。。catch就不能处理Son中的异常。
//多态就不能实现了。
try {
obj.start();
}catch(IOException)
{
//处理IOException
}
}
}
}
十三、Scanner中next nextLine
1、next:读取到空白符结束(空格 回车 tab等)
2、nextLine:读取到回车符结束
3、示例:
1)代码1:
public static void main(String[] args) {
System.out.println("请输入第一个字符串");
String s1=input.next();
System.out.println(s1);
System.out.println("请输入第二个字符串");
String s2=input.nextLine();
System.out.println(s2);
}
2)运行结果1:
请输入第一个字符串
花开花落的 丰富的
花开花落的
请输入第二个字符串
丰富的
3)分析1:
next遇到空格结束 并将空格及空格后的内容滞留在缓冲区
nextLine:将next中滞留的内容输出(即接收到next中滞留的内容)
源码2:
public static void main(String[] args) {
System.out.println("请输入第一个字符串");
String s1=input.nextLine();
System.out.println(s1);
System.out.println("请输入第二个字符串");
String s2=input.next();
System.out.println(s2);
}
结果:
请输入第一个字符串
花开花落 发生的
花开花落 发生的
请输入第二个字符串
af
af
分析:
nextLine:遇到空白符不会结束 遇到换行符结束,且不会把换行符滞留缓冲区
第四章、java核心类库
参考文章:
java核心类库
一、泛型
1、泛型机制的限制:
1)不能实例化类型变量, 如T obj = new T ();
2)不能实例化泛型数组,如T [] arr = new T[3];
【注意】这里不合法仅指实例化操作(new), 声明是允许的 例如T [] arr
2、泛型的特性:泛型只在编译阶段有效。看下面的代码:
List<String> stringArrayList = new ArrayList<String>();
List<Integer> integerArrayList = new ArrayList<Integer>();
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();
if(classStringArrayList.equals(classIntegerArrayList)){
Log.d("泛型测试","类型相同");
}
运行结果:D/泛型测试: 类型相同。
【注意】:
i、通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
ii、泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
iii、定义的泛型类不一定要传入泛型类型实参。如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。
iv:泛型的类型参数只能是类类型,不能是简单类型。
1、泛型类:类型变量T放在类名的后面
1)形式:
单泛型:public class Foo <T> {}
多泛型:class MorePoint<T,U,A,B,C>{}
即在类名后面加一个尖括号,括号里是一个任意大写字母。T一定是派生于Object类的
2)注意:
虽然任意一个大写字母都行,但最好见名知意:
E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
K,V — Key,Value,代表Map的键值对
N — Number,数字
T — Type,类型,如String,Integer等等
3)源码
public class Foo <T> {
// 约定实例变量的类型
private T data;
// 约定返回值的类型
public T getData () {
return this.data;
}
// 约定传入参数的类型
public void setData (T data) {
this.data = data;
}
}
2、泛型方法
1)常用格式:
访问修饰符 [static][final] <类型参数列表> 返回值类型 方法名([形式参数列表])
泛型方法可以是实例方法或静态方法,类型参数可以在静态方法中,这是与泛型类最大的区别。
2)泛型方法的好处
泛型方法可以让不同方法操作不同类型,且类型还不确定。
与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。
3)源码示例
public class GenericTest {
/*
* <T> 声明一个泛型方法
* T:申明该方法的返回值类型是T
* Class<T> 用来指明泛型T的具体类型
* c:用来创建泛型T代表的类的对象
*/
public <T> T getObject(Class<T> c)throws Exception{
T t=c.newInstance();
return t;
}
public static void main(String[] args) throws Exception {
GenericTest genericTest=new GenericTest();
//obj:User类的实例 Class.forName("afterstudy.generic.User"):指定泛型的具体类型
Object obj=genericTest.getObject(Class.forName("afterstudy.generic.User"));
}
//注意
//定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
// Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。
}
3、泛型接口:
1)形式:interface Info<T>
2)当实现泛型接口的类,未传入泛型实参时:
未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
即:class FruitGenerator<T> implements Generator<T>{
如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
源码:
public class FruitFenerator implements Generator<T>{
public T next(){
return null;
}
}
public class FruitFenerator<T> implements Generator<T>{
public T next(){
return null;
}
}
分析:
第一种形式将会报错:Cannot resolve simble 'T'
3)当实现泛型接口的类,传入泛型实参时:
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
4、泛型通配符:
<? extends Fruit>:指定上届
<? super Apple>指定下届
<?>没有限制
public static void main(String[] args) {
//上层限定
Plate<? extends Fruit> p=new Plate<Apple>();
//下层界定
Plate<? super Apple> p2=new Plate<Fruit>();
//Plate<Fruit> p1=new Plate<Apple>();
}
5、静态方法与泛型
静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。
public static void show(T t){..},此时编译器会提示错误信息:
"StaticGenerator cannot be refrenced from static context"
public static <T> void show(T t){}
6、泛型限制类型
1)格式:<T extends 类或接口1&接口2>
限制必须是某某类的子类 或某某接口的实现类
interface Fruit{}
class Apple implements Fruit{}
class Plate<T extends Fruit>{
T data;
}
6、资料:
https://blog.csdn.net/s10461/article/details/53941091?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
二、java.util.Objects
1、Objects 与 Object 区别
Object 是 Java 中所有类的基类,位于java.lang包
Objects 是 Object 的工具类,位于java.util包。用final修饰,不能被继承
2、Objects类中的方法
1)构造方法
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
只有一个构造函数且声明为private,构造函数中抛出一个AssertionError。意味着:这个类不可以实例化。
2)判断两个对象是否相等
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
在普通的equals中,null直接调用equals会报错,但Objects不会
public class Demo1{
public static void main(String[] args){
Person p1=null;
Person p2=new Person();
System.out.println(p1.equals(p2));//报错
System.out.println(Objects.equals(p1,p2));//正确
}
}
3)判断该两对象是否相等
public static boolean deepEquals(Object a, Object b) {
if (a == b)
return true;
else if (a == null || b == null)
return false;
else
return Arrays.deepEquals0(a, b);
}
4)判断对象是否为空:不为空返回true 为空抛出异常
public static <T> T requireNonNull(T obj){
if(obj==null)
throw new NullPointerException();
return obj;
}
5)判断对象是否为null 部位null返回true 为null返回false
public static boolean nonNull(Object obj){
return obj!=null;
}
6)与nonNull相反
public static boolean isNull(Object obj){
return obj==null;
}
4)toString
public static String toString(Object o) {
return String.valueOf(o);
}
Object.equals方法内调用的是return (this == obj)
String类中是依据字符串内容是否相等来重定义了equals方法。
Objects.equals方法中已经做了非空判断
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
三、java.lang.Math
1、绝对值
Math.abs(-100)
2、最大值 最小值
Math.min(100,200);
Math.max(100,200)
3、四舍五入
Math.round(3.5)
4、返回大于等于参数的最小整数
Math.ceil(3.5)
5、返回小于等于参数的最大整数
Math.floor(3.5)
四、java.util.Arrays
1、输出
int[] arr={3,2,4,5,1,4}
System.out.println(Arrays.toString(arr));
2、排序
Arrays.sort(arr);
3、数组扩容
arr=Arrays.copyOf(arr,15);
五、java.math.BigDecimal
1、常用构造方法
public BigDecimal(String val){
}
2、常用方法
public BigDecimal add(BigDecimal augend);//加法运算
public BigDecimal substract(BigDecimal augend);//减法运算
public BigDecimal multiply(BigDecimal augend);//乘法运算
public BigDecimal divide(BigDecimal augend);//除法运算
3、源码
public static void main(String[] args) {
BigDecimal b1=new BigDecimal("0.1");
BigDecimal b2=new BigDecimal("0.2");
BigDecimal b3=b1.add(b2);
System.out.println(b3);
}
六、java.util.Date
1、
public static void main(String[] args) {
Date date=new Date();
long time=date.getTime()-(1*60*60*1000);
Date date2=new Date(time);
System.out.println(date);
System.out.println(date2);
}
2、运行结果
Sat Oct 17 21:34:04 CST 2020
Sat Oct 17 20:34:04 CST 2020
七、java.text.DateFormat
1、DateFormat
y:年 M:月 d:日 H:时 m:分 s:秒
public static void main(String[] args) throws ParseException {
SimpleDateFormat format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String text=format.format(new Date());
System.out.println(text);
Date date=format.parse("2021年12月20日 12:20:40");
System.out.println(date.getTime());
System.out.println((new Date().getTime()-date.getTime())/1000/60/60/24);
}
八、java.util.Calendar
九、String
十、java集合类
java集合类