Java基础

Java学习(尚硅谷)

Java基础部分

Java基本概念

1.“/**……*/”为文档注释语法,好处在于可以通过“javadoc -d 文件夹名称 -anthor -version 文件名.java”命令生成一个文件夹,通过index.html文件可以在浏览器中查看为该文件所作的文档注释——这是文档注释所特有的功能,单行注释及多行注释都不具备。

2.在Java源文件中可以有多个class,但是最多只能有一个类声明为public,且只能加在与源文件同名的类名前面。

3.程序的入口是main方法,格式时固定的,public static void main(String[] args){}。

4.System.out.println()①首先注意不是printlin。②该方法先输出后换行,对应的print()就只输出不换行。③可以通过System.out.println()实现只换行的功能。

5.“.class”称为字节码文件。

Java语法

1.关键字与保留字
2.标识符

①Java中严格区分大小写,长度无限制(26个英文字母,0~9数字,_和$)

②命名规范:

包名:多单词组成时所有字母都小写;

类名、接口名:多单词组成时,所有单词的首字母大写;

变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写;

常量名:所有字母都大写;

3.变量

①Java每个变量必须先声明且赋值,后使用;

②基本数据类型(byte,short,int,long/float,double/char/boolean)+引用数据类型(class/interface/[])

a.字符串的数据类型属于类

b.声明long型变量,必须以“l”或“L”结尾,一般定义整型变量时使用“int”

c.声明浮点型变量默认为double类型,声明float型变量,须加“f”或“F”

d.虽然float只占四个字节,但是能表示的数的范围比占8个字节的long型变量还大,因为后面几位表示的是10的多少次方

e.定义char型变量通常使用一对’’,内部只能写一个字母

f.char c = '\n’转义字符表示方式/char c = '\u0043’这是Unicode值表示方式(此处为C)

g.boolean型变量的值只能是“true”或者“false”

③自动类型转换及强制类型转换

a.char、short、byte->int->long->float->double(前三个两两计算所得数据类型为int)

b.强制类型转换 int i = (int) d;//截断操作,损失精度

④字符串类型“String”

a.String可以和8种基本数据类型作连接运算(+)

算数运算符

a.取余运算,结果的符号与被模数的符号相同

b.自增运算不会改变本身变量的数据类型

c.逻辑“与或非”——“& && | || ! ^”

注意:&与&&执行结果一样,区别在于当前面的条件为false的时候,&执行后面判断条件,&&不执行,或运算与之类似。开发中推荐使用&& ||

d.位运算“与或取反”——“& | ~”

e.三元运算符可以嵌套使用,如:

String MaxStr = (m > n)? “m大”: ((m == n)? “m和n相等”: “n大”)

f.如果程序既可以使用三目运算符,又可以使用if-else结构,那么优先选择三目运算符。原因:简洁、执行效率高。

使用Scanner从键盘获取int类型数据

import java.util.Scanner;//1.导包

class ScannerTest{

public static void main(string[] args){
	Scanner scan = new Scanner(System.in);//2.实例化
	int num = scan.nextInt();//3.调用Scan类相关方法,next获取字符串,nextDouble,nextBoolean(如果要获取char字符,可以用String.charAt(0))
	System.out.println(num);
}

}详情可参考尚硅谷b站学习视频P148

//如果输入的数据类型与要求的数据类型不匹配时,会报异常:InputMisMatchException,导致程序终止。

//Math.random可以返回一个double类型的随机数【0.0~1.0),如果要获取范围为[a,b]的随机数,公式:(int)Math.random()*(b-a+1)+a

分支结构:if-else,switch-case

1.如果switch(number) case分支中没有加break,则满足入口条件进入后后面的条件不判断,语句都执行。

2.switch-case结构中的表达式,只能是如下6中数据类型之一:byte、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)

3.如果switch-case中的语句相同可以合并写成:case0:case1:case2:System.out.println("***");

4.switch-case典型应用——输入几月几号,返回是该年的第几天,提示:①从大到小写②不写break③对前一个月的天数求和

5.写分支结构中,既可以用switch-case,也可以用if-else时,优先选择switch-case,因为效率更高。(case的数量不能太多)

循环结构:for,while,do-while

1.最大公约数、最小公倍数问题:先比较二者选出较小的值,整除为条件,递减求最大公约数;最小公倍数与之类似,先比较二者选出较大的值,整除为条件,递增求最小公倍数。

2.写while循环时要注意不要遗漏迭代条件,避免出现死循环。

3.不能确定循环的次数的时候,可以用while(true)+break或者for(;;)的方式编程。(如题:输入不确定个数的数,判断正负数的个数,尚硅谷教程中P117的写法个人感觉有误,无法人为停止程序——while死循环,此外如果在输入0后还想输入别的值也不行——break)。

4.嵌套循环,倒的金字塔型——注意可以通过内层循环条件改为j<n-i的方式实现金字塔的“倒”置。

5.“菱形”问题——把问题看成空格和指定图案(如*)两部分的组合问题,采用嵌套循环的方法。

6.指定范围内的素数问题——通过标志变量实现遍历后输出,通过break和循环条件中的Math.sqart开方限定范围进行优化,如一万以内素数的个数问题,未优化前需要17110ms,加break后需要1546ms,限定开方范围后需要13ms,此为性能优化问题,此处的开方条件的限定需要好好思考一下。

7.可以通过label:for(……)……continue/break label;的方式实现直接结束指定标识的循环结构。

8.return可以直接结束整个方法,不管return处于多少层循环内,主要用于直接结束整个方法。

数组

1.数组属于引用数据类型(类、数组、接口)的变量。

2.数组的元素既可以是基本数据类型,也可以是引用数据类型。

3.数组的静态初始化(数组的初始化和数组元素的赋值操作同时进行):int[] ids;ids = new int[]{1001,1002,1003,1004};或者int[] ids = {1,2,3,4,5};

4.数组的动态初始化(数组的初始化和数组元素的赋值操作分开进行):String[] names = new String[5];

5.内存结构(堆、栈、方法区)栈:局部变量 堆:new申请的内存区域,通过堆空间的首地址值与栈空间连接起来,理解的时候要先从main入口开始理解。

6.二维数组的静态初始化:int[][] ids;ids = new int[][]{{1001,1002,1003},{1004},{1005,1006}};

7.二维数组的动态初始化(可以只声明行数):String[][] names = new String[5][];

8.二维数组的长度为行数,某个数组元素的具体长度再具体问题具体分析;

9.遍历二维数组:
{

for(int i = 0;i < array.length;i++){
	for(int j = 0; j < array[i].length;j++){
		System.out.println(array[i][j]);
}

}

10.二维数组内存解析:如果二维数组在定义时指明了行数和列数,二维数组的外层元素存放的是堆中的内存地址,如果只指明了行数没有指明列数且没有初始化,则二维数组的外层元素为null,与数组数据类型无关,理解为外层指定了数组的行数,内层指定了一维数组的类型,但是由于引用数据类型没有赋值,所以为null。

(如:array[i]——[I@15db9742)(如:array——[[I@6d06d69c)"["表示一维数组 "I"表示Int类型 @后面的为地址

总结:array为堆中申请的指定长度的二维数组的首地址值,array[i]为指定长度的一维数组的首地址值,array[i][i]为指定数据类型的默认值。

11.数组的赋值与复制.0

①直接:array2 = array1;这种做法是把array1的地址赋给了array2,在堆空间中,实际上只有一个数组。不能称作数组的复制。

②真正的数组复制:int[] array2 = new int[array1.length];再利用for循环进行元素的挨个赋值。

12.二分法查找的前提:所查找的数组必须有序

13.衡量排序算法的优劣:

①时间复杂度:关键词的比较次数和记录的移动次数

②空间复杂度:分析排序算法中需要多少辅助内存

③稳定性:若A和B的值相等,排序后不改变A和B的先后顺序,则该算法是稳定的

14.十大内部排序算法:

选择排序:直接选择排序、堆排序

交换排序:冒泡排序快速排序

插入排序:直接插入排序、折半插入排序、Shell排序

归并排序、桶式排序、基数排序

15.java.util.Arrays工具类

①boolean equals(int[] a,int[] b) 判断两个数组是否相等

②String toString(int[] a) 输出数组信息

③void fill(int[] a,int val) 将指定值填充到数组中(全部替换)

④void sort(int[] a) 对数组进行排序

⑤int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值

16.数组常见异常:

①数组角标越界异常:ArrayIndexOutOfBoundsException

②空指针异常:NullPointerException

Java面向对象学习的三条主线

Java类及类的成员

属性、方法、构造器;代码块、内部类

1.面向对象与面向过程:

①面向过程(Procedure Oriented Programming),强调的是功能行为,以函数为最小单位,考虑怎么做;

②面向对象(Object Oriented Programming),强调具备了功能的对象,以对象为最小单位,每个对象各具备哪些功能,考虑由谁来做;

面向对象程序的设计就是类的设计

属性 = 成员变量 = field (身高、体重等属性)

方法 = 成员方法 = 函数 = method(打球、吃饭等行为)

使用:①创建类,设计类的成员class XXX(){} ②创建类的对象 XXX xx = new XXX(); ③通过xx.**调用对象的属性或者结构。

2.直接定义在类的{}内的,称为成员变量(属性),存储在堆空间中的,定义在方法形参、方法内、代码块内、构造器形参、构造器内的变量(局部变量)是存在栈空间中的。

3.属性与局部变量的对比

①属性(成员变量)前面可以添加权限修饰符(public\private\protected\缺省),局部变量不可以加权限修饰符。

②属性是有默认初始化值的,局部变量没有默认初始化值,意味着局部变量在调用前必须要赋值,特别的,形参在调用时赋值即可。

③属性:加载到堆空间中(非static)局部变量:加载到栈空间。

4.方法的声明 权限修饰符 返回值类型 方法名(形参列表){
方法体
}

5.类的声明不加“()”!!!方法声明才加!!!

6.类的方法中不能定义方法,可以调用方法,可以调用属性及定义变量。每一个方法是具有特定功能的。

7.(非匿名类)匿名对象的使用

①没有显式地定义一个变量名来实例化对象,如:new Phone();

②一般配合形参使用,如:

PhoneMall mall = new PhoneMall();
mall.show(new Phone);
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}

注意:

①还有对应的匿名子类(非匿名对象),如:Person p = new Person{quick fix——>Add unimplemented methods}注意这里后面的Person是父类抽象类,不可以用来实例化对象,以“{}”的方式声明Person的子类,因此为匿名子类。

②此外还有匿名子类匿名对象,如method(new Person{quick fix——>Add unimplemented methods}),既没有对象名也没有类名。

8.重载:重名的方法,只要其参数个数或参数类型不一样即可。“两同一不同”——类相同、方法名相同、参数列表不同。是否是重载与权限修饰符、返回值类型、形参变量名、方法体都无关。

9.可变个数形参?JDK5.0新特性,如:public void show(String … strs){}

①与本类当中方法名相同、形参类型也相同的数组之间不能共存

②要声明的话只能声明在末尾,指的是String … strs这个要放在入口参数的最后一个

③同一个方法中,形参中只能声明一个可变个数形参

如果使用数组方式定义则:public void show(String[] strs){},在前面实例化后调用时,需要xxx.show(new String[]{“aa”,“bb”,“cc”}),若使用可变个数形参则可以省去new String[]的过程直接写成xxx.show(“aa”,“bb”,“cc”)即可,遍历的时候把可变个数形参当成数组写即可。

主要应用场景在SQL数据库查询中where条件后面,不知道用户需要输入几个限制条件。

10.值传递机制:

交换数据,对普通数据类型,若通过实参传递给形参,方法中形参交换并不会影响实参的值,直接在main方法中打印会导致交换不成功。但是如果实参是引用数据类型,实参赋给形参的是个地址,方法中操作形参时也会交换对应实参的值。

即:

如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。

如:可以通过(int[] arr,int i,int j),数组是引用数据类型,通过序号控制则可以实现“真正的”值传递。

注意:String s1 = "hello"这也是引用数据类型,String比较特殊,可以不通过New来实例化,这里的hello存储在方法区里的字符串常量池里,通过地址对其进行修改的时候,由于hello是不可变的字符序列,只能重新建一个,会导致“值传递机制”“失效”

可参考尚硅谷第213集好好体会值传递机制。

11.递归方法:如计算1-100之间所有自然数的和

public int getSum(int n){
	if(n == 1){
	return 1;
	}else{
		return n + getSum(n-1);
	}
}

递归一定要向已知方向递归,否则会无限递归,类似于死循环。

应用场景:斐波那契数列、汉诺塔问题、快排

12.main()方法的使用说明:

①程序的入口
②普通的静态方法——多个main方法的时候,其中一个是程序入口,另一个就是普通的静态方法
③可以作为我们与控制台交互的方式(之前使用的是Scanner)
Eclipse——>编译生成字节码文件——>右键Run As——>Run Configurations——>自动定位到当前程序——>Arguments——>Program arguments中填写的值就可以赋值给main函数的入口形参
cmd控制台——>把源代码中的首行包名删除——>javac xxx.java——>java xxx——>java xxx 输入想要赋值的值,空格间隔,回车结束

注意:main()方法在执行之前会先调用类,而不是直接执行首行代码

13.代码块

13.1 代码块的作用:用来初始化类、对象,因此也叫“初始化块”

13.2 静态代码块、非静态代码块

静态代码块:会随着类的加载而加载并且执行,与属性、方法只加载不自动执行不同——>类的初始化
非静态代码块:会随着对象的实例化而执行,同样与属性、方法不同;每创建一个对象,就执行一次非静态代码块——>在创建对象的时候,对对象的属性进行初始化。

13.3 使用距离

比如有需要执行之前的单例模式中的懒汉式写法的时候,既可以通过“null”判断的方式来写,也可以通过代码块的方式——>一般用于需要进行一些操作,但是只执行一次时候的操作。

13.4 程序运行的顺序——由父及子,静态先行

父类静态代码块——>子类静态代码块——>父类非静态代码块——>父类无参构造器——>父类有参构造器——>子类非静态代码块——>子类无参构造器——>子类有参构造器
即:静态代码块——>非静态代码块——>构造器

注意:再次声明对象的时候,静态部分随着类的加载执行过一次后不执行了!!!总是会忘!!!

14.内部类

当定义成外部类时与某一类并列关系感觉不合适,放到该类中以变量的方式声明又不足以描述清楚

14.1 分类可分为成员内部类(直接定义在类内部的类)(静态、非静态)及局部内部类(定义在方法内、代码块内、构造器内的内部类)

一方面,作为外部类的成员——>
①调用外部非静态方法时需要使用“外部类名.this.方法名”的方式②可以被4中权限修饰符修饰
另一方面作为类——>
①可以声明属性、方法、构造器②可以被final、abstract修饰,分别表示(不可继承、不可实例化)

14.2 如何实例化成员内部类的对象

静态成员内部类:外部类名.内部类名 对象名 = new 外部类名.内部类名();
非静态成员内部类:①先实例化外部类②外部类名.内部类名 对象名 = 外部实例对象名.new 内部类名();

14.3 如何在成员内部类中区分调用外部类中的结构

内部类形参名——>变量名
内部类属性——>this.变量名
外部类属性——>外部类名.this.变量名

14.4 开发中局部内部类的使用

一般用于返回一个创建了对象的实现类,与创建匿名对象匿名实现类的方式类似,区别在于用内部类实现是匿名对象有名实现类的方式(标准方式)

14.5 成员内部类和局部内部类编译后都会生成对应的字节码文件,格式为:

成员内部类:外部类$内部类名.class
局部内部类:外部类$数字(方法内、代码块内、构造器内可能重名) 内部类名.class

14.6 注意点——>安卓开发中需要注意

局部内部类在调用方法内的局部变量时,会要求该局部变量为常量,如果声明为int x = 8;在JDK8及以上不用显式加上“final”,实际上还是个常量,而JDK7以前需要显式加上final字样
三大特征

1.封装与隐藏

①通过权限修饰符将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)属性。

②不对外暴露的私有的方法

③单例模式,构造器……

④如果不希望类在包外被调用,可以将类设置为缺省的

备注:四种体现:属性私有化、方法私有化、构造器私有化、类的私有化

2.四种访问权限修饰符

private < 缺省 < protected < public

private只能类内部调用;缺省只能同一个包调用;protected只能不同包的子类调用,public可以同一个工程调用。

都可以用来修饰类的内部结构:属性、方法、构造器、内部类;

修饰类的话只能用缺省或者public

权限不够调用时会提示:is not visible

3.类的结构之三:构造器(constructor)

①构造器的作用:创建对象(new + 构造器),并且可以在创建对象的时候初始化对象的属性。

如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
定义构造器的格式:权限修饰符 类名(形参列表){}
一个类中定义的多个构造器,彼此构成重载。
一旦定义了构造器之后,系统不再提供空参构造器,如果需要空参的构造器需要自己定义重载。

4.JavaBean是指符合如下标准的Java类

类是公共的
有一个空参的公共的构造器
有属性,且有对应的get、set方法

5.UML类图

+表示public,-表示private,#表示protected
外层左上角为包名,中间最上面为类名,下面是属性和方法的一些要求。

6.继承性

①继承性的好处

减少了代码的冗余,提高了程序的复用性
便于功能的拓展
为之后多态性的使用,提供了前提

②继承性的格式:class A extends B{}

子类A继承父类B之后,子类就获取了父类中所有的属性和方法
特别的,父类中声明为private的属性或方法,子类继承后仍然获取了父类中私有的结构,只是由于封装性的影响不能直接调用而已
子类可以声明自己特有的属性和方法,实现功能的拓展

③继承性的规定

类的单继承性:一个类只能有一个父类
多层继承关系:子父类是相对的概念,直接继承的称为直接父类,间接继承的成为间接父类
所有的类都继承于java.lang.Object类

子类可以通过父类的get、set方法或者将父类的private权限的方法放在public权限的方法下面后仍然可以调用来佐证子类可以获取父类private权限的属性或方法。

7.方法的重写(override)

①子类继承父类之后,可以对父类中同名同参的方法进行覆盖操作

②权限修饰符问题:、

子类重写的方法权限修饰符不小于父类被重写的方法的权限修饰符,父类中private权限的方法不能重写,一般来说,如果子类中对父类中的方法进行了重写,那么当父类中调用方法时,会调用子类中重写后的方法,如果调用的还是父类中的方法,说明子类重写并没有成功。

③返回值类型问题:

父类中被重写的方法的返回值是void的情况下,子类重写的方法的返回值只能是void
父类中被重写的方法的返回值是基本数据类型的情况下,子类重写的方法的返回值必须是相同的基本数据类型
父类中被重写的方法的返回值是A类的情况下,子类重写的方法可以使A类及A的子类

④异常的类型(throws 异常的类型):

子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

注意:
① alt+/ 编程提示中会有提示,是否是对父类中的重写快捷键(可在方法上方添加@override注释表明这是方法重写)

② 子类和父类中同名同参数的方法要么都声明为非static的(构成重写),要么都声明为static的(不构成重写),如果一个是static,另一个不是,则会报错。

7.多态性

①父类的引用指向子类的对象,即声明一个父类对象,用子类去new出一个结构,使父类对象名指向子类结构。此时调用的方法是子类中重写过后的方法

②编译看左边,运行看右边,即编译期只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写后的方法。——虚拟方法调用

③多态性好处之一:func(Animal animal){}/test.func(new Dog())/test.func(new Cat())可以通过这种方式避免写很多重载方法,实现多个子类执行同样的步骤的方法。

④对象的多态性只适用于方法,不适用于属性。子父类可以存在同名的属性?怎么从内存上理解?

⑤重载与重写:

对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,称为“早绑定”
对于多态,只有等到方法调用那一刻,编译器才会确定要调用的具体方法,称为“晚绑定”

注意:多态在运行时,会先去调用父类中的方法,如果该方法子类中重写过了,就调用重写后的方法,否则,调用父类中的方法!!!

8.向下转型的使用——“向上转型”指的就是多态,对应的就是向下转型

由于多态性的存在,当定义子类对象结构给父类变量名的时候,编译器会认为此时可以调用的方法是父类中的,会导致不能调用子类所特有的方法、属性。

如何才能调用子类中特有的属性和结构呢?——强制类型转换

如:Man m1 = (Man)p1;但是强转时可能出现ClassCastException的异常。

为了避免该异常的出现导致程序崩溃,使用instanceof关键字,用法为:对象名a instanceof 类名A,判断对象a是否是类A的实例,如果是,返回true,如果不是,返回false。instanceof左右两侧的必须为子父类关系,否则编译不通过。

9.包装类(Wraper)——为了使基本数据类型也可以体现面向对象的思想

byte——Byte
short——Short
*int——Integer*
long——Long
float——Float
double——Double
上述六个都有个父类Number
boolean——Boolean
*char——Character*

9.1 基本数据类型转换为包装类——>调用包装类的构造器

Integer in1 = new Integer(int类型数据)

9.2 基本数据类型包装类在实例化对象的时候,括号内如果放字符串,字符串内不能“混搭”,而Boolean型的括号内可以混搭不报错,重写过的方法功能为,在忽略大小写的前提下,只要字符串内的内容与true不一致,返回false。

9.3 包装类转换为基本数据类型——>先强制转换为对应的包装类,再调用包装类的相关方法xxxValue()

如:Integer inScore = (Integer)obj;
int score = inScore.intValue();

9.4 自动装箱与自动拆箱(JDK5.0新特性)

即自动进行基本数据类型与对应的包装类之间的转换

9.5 基本数据类型、包装类——>String类型

String.valueOf(Xxx xxx)

9.6 String类型——>基本数据类型、包装类

包装类.parseXxx()
可能会报NumberFormatException异常
其他关键字

this\super\static\final\abstract\interface\package\import等

1.this——理解为当前对象,谁调用此方法,对象就是谁

①可以用来修饰:属性、方法、构造器;修饰属性和方法时,理解为当前对象,在构造类的时候不知道对象名称叫什么所以,动态构造为this.Xxx,通常情况下省略“this”关键字,但当方法的形参和类的属性同名时不能省略this.Xxx

②可以用来调用构造器;当构成重载的构造器内有冗余代码时,可以通过this();的方式在构造器内调用构造器,这样会先执行空参构造器内的代码,可以有效解决代码冗余的问题。而this(),这个括号内部放的是什么属性类型,就会调用相应的构造器。可以将本构造器中的形参中的对应参数放进去,调用前面的构造器,如this(age);

注意:不能在构造器内调用本身构造器,也不能回调构造器,不能构成“环”;此外,单个只能调用一个其他构造器。

2.package——为了方便对项目中类的管理,引入此概念

①声明在源文件的首行,使用package声明类或接口所属的包,命名要见名知意;

②每“.”一次,就代表一层文件目录。

③JDK中主要包的介绍

java.lang——核心类,如String、Math、Integer、System和Thread
java.net——网络相关操作的类和接口
java.io——输入输出相关的
java.util——实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数
java.text——java格式化相关的类
java.sql——JDBC数据库编程相关的类/接口
java.awt——抽象窗口工具集——GUI界面,java做客户端才用,现在基本上都通过浏览器访问了。

3.MVC设计模式

①“M”——model,主要处理数据

.bean/domain 数据对象封装
.dao 数据库操作类
.db 数据库

②“V”——view,显示数据

.utils 相关工具类
.ui 自定义view

③“C”——controller 处理业务逻辑

.activity 应用界面相关
.fragment 存放fragment
.adapter 显示列表的适配器
.service 服务相关的
.base 抽取的基类

4.import

1.使用import xxx.*可以导入xxx下的所有结构,但是如果需要导入子包下的类或接口,仍然需要显式导入。

2.如果使用的类或接口是java.lang(常用)或者是本包下的,可以省略import;

3.当需要使用两个不同包下的重名类,则后至少有一个类需要以全名的方式自主调用,而无法通过Import导包,如:

com.atguigu.exer01.Xxx xxx = new com.atguigu.Xxx();

4.import static问题,如System.out.println(),这个out是System类内部定义的一个静态常量,如果在顶部导包中写:import static java.lang.System.*,则代码中可以直接写out.println(),编译器可以找到并使用System类下的静态结构(属性和方法)。

5.super

①super理解为:父类的,可以用来调用属性、方法、构造器

②一般情况下省略,类似于this,super用于子类重写了父类方法后区分调用的方法到底是子类还是父类

③调用构造器,在子类构造器中用super();的方式调用父类中的构造器,括号里的形参列表是什么,调用的就是对应的形参的构造器,用于父类属性声明为private类型后,子类想要给有参构造器赋值时。

③this(形参列表)和super(形参列表)只能出现一个,无论出现哪个,都需要放在构造器内的代码首行。

④如果子类构造器首行没有显式声明super,则会默认调用super();即父类的空参构造器。

6.static

有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份

6.1 可以用来修饰属性、方法、代码块、内部类,不可以修饰构造器、类

6.2 static修饰的属性:

①静态变量——类的多个对象公有一个,修改后所有对象的该属性都会变化。因此,非静态变量也称为“实例变量”,静态变量也称为“类变量”
②静态变量随着类的加载而加载,可以通过“类.静态变量”的方式直接调用
③类只会加载一次,静态变量在内存中也只会存在一份——>存在方法区的静态域中

④举例:System.out、Math.PI、Collections|单例模式|

6.3 static修饰的方法:

①随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
②由生命周期决定——静态方法只能调用静态属性或方法、非静态方法既可以调用静态的也可以调用非静态的。
③静态方法中不可以使用this、super,因为this和super都是针对具体对象来说的

由于类的加载先于对象的加载(甚至对象都不加载),因此,不能通过类直接调用非静态的属性或方法,非静态的属于具体对象所有

6.4 开发中如何确定属性、方法是否要声明为static的?

类中的常量也通常声明为static类型
多个对象所共享的属性,不会随着对象的不同而不同的属性可以声明为静态属性

操作静态属性的方法、工具类中的方法,习惯上声明为static的

可以通过在构造器中通过静态变量的自增来实现类似计数或者自动生成ID的功能,需要注意,每种构造器中都要有对应的自增语句,可以通过使用this()的方式

7.(必须熟悉会写)单例模式(Singleton)——关于创建型模式、结构性模式、行为型模式,一共有23种设计模式(通用)——>“套路”

在开发中,使某个类只能存在一个对象实例

7.1 如何实现?

饿汉式实现:
①私有化类的构造器,否则类的外面可以声明多个实例
②内部创建类的对象,如:private static Bank instance = new Bank();
③提供公共的方法,返回类的对象,如public static Bank getInstance(){return instance;}
此时通过Bank bank1 = Bank.getInstance()实现实例化,以这种方式无论实例化多少个对象,实际上,都指向同一个地址,是同一个实例。
懒汉式实现:
①私有化类的构造器
②声明当前类的对象,但是没有初始化,如:private static Order instance = null;
③声明public、static的返回当前类对象的方法,如public static Order getInstance(){if(instance == null){instance = new Order();}return instance;}
二者对比:
饿汉式:坏处:占用内存,对象加载时间过长;好处:线程安全;
懒汉式:好处:延迟对象的创建;坏处:目前的写法不安全,可能会有多个线程同时进来以后,new多个实例出来。
举例:java.lang.Runtime;网站的计数器;应用程序的日志应用;数据库连接池;项目中读取配置文件的类;Application;Windows的Task Manager(任务管理器);Windows的 Recycle Bin(回收站)

7.2 另外一种单例(*)

①先私有化类的构造器
②打开属性权限——>public static final Bank instance = new Bank();
static的作用是保证instance在类加载的时候仅创建一次,实现“单例”要求,final的目的是为了防止用户在类外通过调用属性的方式将instance恶意赋值为null,static是公有属性,会导致所有的对象都变为null。

8.final

8.1 用来修饰一个类——>不能被继承(太监类),如:String类、System类、StringBuffer类

8.2 用来修饰方法——>不能被重写,如getClass();

8.3 用来修饰变量——>常量

1.final修饰的属性,可以在哪些位置对属性进行赋值?
①显式初始化(常量要所有字母大写)、代码块中初始化、构造器中初始化——>对象一创建就需要对常量进行赋值
②不能通过显式初始化、不能在方法中进行初始化
③多个对象该常量相同——>显示初始化赋值;多个对象该常量不相同——>构造器中赋值;需要调用方法且可能会抛出异常——>代码块中赋值
2.final修饰局部变量(形参、方法内变量)——常量、可调用不可修改(注意:形参也包括对象!!)
3.static final——>修饰属性——>全局常量;——>修饰方法——>通过类调用且不可重写(很少自己写)

9.native——表明涉及到本地底层C/C++代码了,相当于一种隐藏。

10.abstract——抽象类与抽象方法

随着继承的深入,父类越来越抽象、子类越来越具体,当不想让父类再被用来实例化对象时,用abstract

10.1 可以用来修饰:类、方法

抽象类:
①此类不能实例化②抽象类中一定有构造器,虽然自己不能实例化,但是子类需要继承父类的构造器进行实例化
抽象方法:
①抽象方法只有方法的声明,没有方法体,主要用于规定该抽象类的子类中必须有该方法,但是方法的具体内容根据对象的不同而不同,如:public abstract double findArea();
②包含抽象方法的类一定是个抽象类
③若子类重写了父类中的所有抽象方法,则此子类方可实例化,否则子类还是个抽象类

10.2 abstract在使用上的注意点

①不能修饰:属性、构造器等结构
②不能修饰私有方法——需要重写但是私有的方法不允许重写、静态方法——抽象方法需要重写但是子父类中的静态同名函数并不算是重写、final方法——不允许修改与必须要重写冲突、final的类

10.3 abstract举例:①几何图形求面积,不同几何体求面积方法不同,但是都需要求面积②IO流设计到的抽象类:InputStream/OutputStream/Reader/writer。在其内部定义了抽象的read()、write()方法

11.模板方法设计模式——确定的结构+不确定的部分(易变的部分)

11.1 如:

abstract class Template(){
	public void spendTime(){
		long start = System.currentTimeMillis();
		this.code();
		long end = System.currentTimeMillis();
		System.out.println("花费的时间为:" + (end - start));
	}
	public abstract void code();
}

Template的子类中通过对code的重写后即可套用此模板,而在重写之间,抽象方法对应的部分为不确定的部分

11.2 模板方法设计常见于:

①数据库访问的封装
②JUnit单元测试
③JavaWeb的Servlet中关于doGet/doPost方法调用
④Hibernate中模板程序
⑤Spring中JDBCTemplate,HibernateTemplate等

12.Interface

12.1 Java中接口和类是并列的两个结构

12.2 如何定义接口,定义接口中的成员

JDK7以前:只能定义全局变量和抽象方法
①全局变量:public static final书写时可以不写,默认就是全局变量
②抽象方法:public abstract书写时也可以不写,默认是抽象方法
JDK8新特性:还可以定义静态方法(public static)和默认方法(public default)
①方法声明中的public可以省略,默认权限还是public
②接口中定义的静态方法是不可以通过实现类调用的,只能通过接口调用
③可以通过实现类调用接口中的默认方法,如果实现类中重写了该方法,则调用重写后的
④如果子类(或实现类)继承的父类和实现的接口中定义了同名同参的方法,子类在没有重写该方法的情况下默认调用的是父类中的方法。——>类优先原则(相对接口中的方法来说)
⑤如果实现类实现了多个接口,多个接口中存在同名同参数的方法,在实现类中没有重写的情况下报错——>接口冲突
⑥method();调用实现类中自己定义的方法/super.method();调用子类继承父类中的方法/接口名.super.method调用接口中的默认方法,静态方法的话可以直接“接口名.method”,默认方法有些特殊

12.3 接口中不可以定义构造器,意味着接口不可以实例化,但是可以通过接口的“实现类”(implements)实现,如果该实现类实现(本质上就是重写,这里为了和子父类中的重写区分,称为实现)了接口中的所有抽象方法,则可以实例化

12.4 Java可以实现多个接口——>弥补了Java单继承的局限性

格式:class AA extends BB implements CC,DD{}

12.5 接口与接口之间可以继承,而且可以多继承

12.6 接口的具体使用体现了多态性(接口的实现类),接口实际上可以看做是一种规范,即某种功能必要哪些步骤……——>面向接口编程

12.7 (了解)代理模式——>如:(静态代理)通过代理服务器调用相关登录方法,构造器形参声明为对应接口,再在主函数中用实际服务器构造对象,通过代理服务器的接口形参构造器进行调用。

12.8 (排错题)当一个类的父类和其使用的接口中含有同名的属性时,由于类和接口是并列结构,编译器并不知道该用哪个,如果想要调用父类中的需要使用“super.x”,如果想调用接口中的直接“接口名.x”就可以了

12.9 (排错题)当接口多继承时,继承的接口中如果定义了同名的方法,则重写该方法认为是对两个被继承接口中该函数的重写;此外接口中声明的为常量,一般省略关键字,但是需要注意,后面调用的时候常量是不可以修改值的。

Eclipse相关

1.复制源文件到项目中时若出现乱码,打开源文件后另存为时修改编码方式为utf-8,再重新复制即可。

2.workspace中项目文件较多时,可以将project关闭,通过filter过滤已关闭的project来简洁化workspace。

3.关联源码,通过ctrl+鼠标左键,选择jdk里面的src压缩包进行关联。

4.Window->Preferences->Java->Code Style->Code Templates->Comments->Types&Methods修改过作者信息之后,可以在代码中通过/**+enter的方式快捷加入文档注释

5.Source->Generate Getters and Setters可以直接生成对应属性的get和set方法。

6.Source->Generate Constructor using Fields可以直接生成对应属性的构造器。

7.Window——>Preferences——>Java——>Editor——>Content Assist——>Auto Activation中将“.”改成“abcdefghijklmnopqrstuvwxyz.”则可以实现编程全程提示。

8.Window——>Preferences——>搜索keys——>搜索冲突的快捷键——>在下面的Binding中进行修改

9.如何调试程序?

1.System.out.println().通过输出判断哪里出了问题
2.Debug调试:①在想要设置断点的代码最前面双击 ②debug as java application,不是run as了,注意一下 ③Step Into/Step Over/step Return/Resume——>执行到下个断点处,若没有的话则终止,若想要再次开始debug,点Step Return右侧有个臭虫标志,debug as……即可。Drop to Frame——>用于返回当前方法首行,进行回退操作。
3.如果出现Step Into进不去的情况,即Step Into和Step Over现象相同,不是eclipse版本的问题,是Debug As——>Debug Configurations——>JRE——>Alternate JRE(这里的JRE因为不是JDK里面的JRE,是单独安装的JRE就会出现上述问题,修改方法如右边)——>Install JRES——>把原来的Remove——>add——>standard VM——>JRE home(选择对应的JDK文件目录)

10.单元测试——JUnit

想要测试哪部分代码就只执行哪部分代码

10.1 选中当前工程右键——>Build Path——>Add Libraries——>JUnit——>JUnit4(默认)

10.2 创建java类,进行单元测试,要求:此类是public的,提供公共的无参的构造器

10.3 声明单元测试方法,方法的权限是public,没有返回值,没有形参——与main方法功能类似,提供一个程序入口,但结构不同!

10.4 需要加上@Test注解,并在单元测试类中导包:import org.jUnit.Test
1
10.5 写完代码以后,左键双击单元测试方法名(一般命名为test+想要测试的类名()),右键run as——>JUnit Test

10.6 如果执行没有异常,进度条是绿色的,如果执行产生异常,进度条为红色

10.7 可以在测试类中定义属性,且不用通过像main方法中那样先声明当前类的对象再调用,而是可以像普通方法一样直接调用,因为main方法时static静态的,而定义的普通方法时非静态的。

10.8 开发中直接@Test,可以快捷实现第一步和第四步!!

异常处理

1.Java程序在执行过程中所发生的异常事件可分为两类

①Error:Java虚拟机无法解决的严重问题,如:JVM系统内部错误,资源耗尽:StackOverflowError、OOM(OutOfMemoryError),一般不编写代码进行处理
②Exception:其他因编程错误或偶然的外在因素导致的一般性问题,如:空指针、试图读取不存在的文件、网络连接中断、数组角标越界

2.异常体系结构

java.lang.Throwable
	-----java.lang.Error;
	-----java.lang.Exception;
		-----编译时异常(checked)
			-----IOException
			-----FileNotFoundException
			-----ClassNotFoundException
		-----运行时异常(unchecked)——>RuntimeException
			-----NullPointerException
			-----ArrayIndexOutOfBoundsException
			-----ClassCastException
			-----NumberFormatException
			-----InputMismatchException
			-----ArithmeticException

3.抓抛模型

过程一:“抛”,程序在执行过程中一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出。一旦抛出异常,其后的代码就不再执行。
过程二:“抓”,异常的处理方式——①try-catch-finally②throws

3.1 try-catch-finally

try{
	可能出现问题的代码
}catch(异常类型1 变量名1){
	处理异常的方式1
}catch(异常类型2 变量名2){
	处理异常的方式2
}
……
finally{
	一定会执行的代码
}

①finally

①是可选的结构,不一定非要写。
②finally中是一定会执行的语句,即使catch中也出现了异常或者try/catch结构中存在return语句。
③像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,需要手动释放资源,声明在finally中实现一定会关闭该连接。

②在没有写finally的情况写,一旦某一条catch语句匹配了异常类型,自动跳出try-catch结构,继续执行后面的代码。

③catch中的异常类型如果没有子父类关系,谁声明在上面或下面无所谓,但是如果存在子父类关系,父类必须放在下面,否则会编译错误。

④常用的异常类型处理方式:System.out.println(e.getMessage);/e.printStackTrace();

⑤在try{}里定义的变量,出了try结构不能再被调用,如果非要用,可通过“在外部声明,在内部赋值的”方式解决

⑥快捷键——>选中需要用try-catch包围的代码块,右键——>Surround With——>Try/catch Block

3.2 throws + 异常类型

写在方法的声明处,指明此方法执行时可能会抛出的异常类型,一旦发生异常,会在异常代码处生成异常类的对象,此对象满足throws后面的异常类型时,就会被抛出,异常代码后面的代码不被执行。

3.3 子类抛出的异常不能大于父类的原因

因为多态性的存在,开发中常常会用父类声明的对象实现try-catch操作,但是真正运行时可以传入子类结构声明的对象,如果子类抛出的异常大于父类,则会导致try-catch不能解决该异常。

3.4 开发中如何选择try-catch-finally还是throws?

①如果父类中被重写的方法没有throws方式处理异常,由于子类抛出的异常不能超过父类,因此,也不能使用throws方式处理异常,因此当子类中有可能出现异常时,使用try-catch-finally处理。
②当执行的多个方法之间为递进关系,各自使用throws抛出异常,而当几个方法被一个整体方法调用的时候,该整体方法内使用try-catch-finally进行处理,因为递进关系的存在,如果方法一出现了异常,得不到想要的数据,后面的方法也没有必要执行,因此使用try-catch-finally直接处理掉即可。

4.异常处理最大的意义在于,程序真的出现异常之后,给用户一个友好的提示,而不是弹出一堆乱码或者程序崩溃,此外,当异常出现后,除了给出友好提示外,可以将异常数据的一些信息发送至后台记录,最终的目的是代码层面修复该问题。

5.关于异常对象的产生

系统自动生成的异常对象
手动生成的异常对象,并抛出——>throw

6.throw的应用场景

如:输入的数据非法——>之前只能以println()的方式输出提示语句,现在可以通过throw方式抛出异常,形式为:return new RuntimeException/Exception("您输入的数据非法!")
如果new RuntimeException(),为运行时异常,编译不报错,运行时报错,并没有进行处理;如果改为new Exception(),编译时就会报错,需要添加throws语句将异常上抛,抛到main函数中之后使用try-catch进行异常的处理

7.如何自定义异常

①继承于现有的异常结构:RuntimeException、Exception
②提供全局常量:serailVersionUID
③提供重载的构造器,参考RuntimeException类,提供两个构造器即可(super(msg);)

数据结构

1.数据与数据之间的逻辑关系:集合、一对一、一对多、多对多

2.数据的存储结构:

线性表:顺序表(如:数组)、链表、栈、队列

树形结构:二叉树

图形结构:

快捷键

1.Ctrl + O 找特定的方法的代码位置(outline)

2.ctrl + shift + o 批量导包

3.shift + enter 光标换到下一新行

4.ctrl + shift + enter 光标换到上一新行

5.alt + / 编程提示功能——补全代码

6.ctrl + shift + f 代码对齐

7.ctrl + 1(这边是阿拉伯数字1) 快速修复,类似于android studio中的alt + enter,可以快捷创建变量或对象。

8.ctrl + shift + / 多行注释

9.ctrl + shift + \ 取消多行注释,注意这边是顿号那个斜杠

10.ctrl + alt + down/up 向下或向上复制选中行代码

11.ctrl + d 删除选中行代码

12.alt + up/down 上下移动选中代码

13.ctrl + shift + t 搜索指定的结构

14.alt + left 回到上一编辑界面,一般用于深入查看结构时返回上一界面(游戏鼠标的左侧两个按键就相当于alt + left和alt + right)

15.ctrl + t 查看继承树结构

16.tap 选中代码整体后移

17.shift + tap 选中代码整体前移

18.ctrl + shift + r 光标放在指定变量或类名后可以批量重命名(或者可以用ctrl+f再批量切换)

19.ctrl + shift + x 选中字母大写

20.ctrl + shift + y 选中字母小写

21.alt + shift + s 快速构造get、set方法及构造器

22.alt + enter 选中对应的文件、包、工程后可以查看属性信息

23.ctrl + k 快速查找,相当于ctrl+f点下一个的功能,区别在于没有对话框显示

24.ctrl + w 关闭当前窗口

25.ctrl + shift + w关闭所有的窗口

26.ctrl + alt + g 查看指定的结构使用过的地方

Object类

1.默认为所有类的根父类

2.Object只有一个空参构造器

3.常用方法:

clone()——克隆对象
equals(Object obj)——详细见3.1
finilize()——堆空间垃圾回收的方法,不要主动调用该方法
getClass()——获取当前对象的所属类
hashCode()
wait()
notify()
notifyAll()

3.1 equals与“==”的区别?

①除了boolean之外的变量都可以用==,基本变量比较的是数据(不一定要类型相同,会有自动类型提升),引用数据类型比较的是地址。

②equals是一种方法,只能由对象来实现调用,因此只适用于引用数据类型。Object类中的equals和“==”的作用相同,比较的是对象的地址,但是如String、Date、File、包装类等类中进行过重写,比较的是对象中的“实体内容”是否相同。

③通常情况下,我们自己写的类中如果需要使用equals方法,都需要重写,因为一般不会想要执行“= =”的功能。手动重写不会写可以参考String类的equals设计方法——先比较地址是否一样,不一样再比较obj是不是该类的实例,如果是再比较两个对象的属性(基本数据类型比较数值,引用数据类型比较内容,注意不要用“==”比较地址!!!)。自动重写的话可以使用快捷键alt+shift+s——>Generate hashCode() and equals()。

④重写equals()方法有4+1条原则——对称性、自反性、传递性、一致性、null

3.2 to String()

①当输出引用对象时(println(对象名)),实际上是调用当前对象的toString方法,输出的是地址,格式为:
getClass().getName() + @ + Integer.toHexString(hashCode())。

②如String、Date、File、包装类等类重写过了toString()方法了,调用时会返回“实体内容”信息。

③自定义的类可以通过快捷键alt+shift+s——>Generate toString()快捷重写该方法。

面试相关

1.快速排序O(nlog2(n))、堆排序、归并排序、冒泡排序O(n^2)

2.几道网红题目:

①System.exit(0)可以直接终止程序。/重写print打印流方法

②让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值,遍历新的数组。

坑:不能从首位置开始,首位置会变成1!

③println(char[])当括号内放了一个char型数组时,实现的是遍历功能,当括号里放其他类型的数组时会调用println(Object o),会输出一个地址值。

3.关于包装类使用的面试题

3.1 如下两个题目输出结果相同么?各是什么?

Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);
//编译的时候要求三目运算符?后面的两个类型可以统一,因此在编译的时候存在一个自动类型提升的问题,答案为1.0
****************************************************
Object o2;
if(true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);
//这题没有自动类型提升,答案为1

3.2 下面两道题各输出什么?

Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
************************************
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//false
原因:Integer类中声明了一个静态的IntegerCache缓存数据,用来提前生成-128 ~ 127的数,当数在这个区间内,会直接调用对应的地址,所以比较地址的时候会相同,但是,128不在该范围内,系统会以new的方式声明新的地址,new出的两个地址比较所以为false

4.谈谈你对多态性的理解

实现代码的通用性:
①Object类中定义的public boolean equals(Object obj){},括号内可以放Object及其子类
②JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server),Java代码中设计父类方法,实际运行时只需要放入对应的子类即可实现通用性。
③抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)

5.抽象类和接口的异同?

相同点:①不能实例化②都可以被继承
不同点:①抽象类有构造器,接口没有②多继承和单继承的区别

6.throw和throws的区别

throw——>手动抛出一个异常类的对象,是生成异常对象的过程,声明在方法体内
throws——>异常处理的一种方式,声明在方法的声明处
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值