javaSE进阶学习笔记

1、关于java的集成开发环境:
eclipse、IntelliJ IDEA等。
其中目前主流的集成开发环境是:IntelliJ IDEA

这只是一个工具,不要让一个工具把你难住了。
开发工具不要使用汉化版,太low。
英语单词太多别害怕,记位置。(一共就那几个主要的操作位置。)

2、IDEA工具的使用:

第一次打开的时候:会弹出一个窗口(import idea settings)
	这个表示导入idea的设置,但我们是第一次使用idea工具,
	没有设置过idea,所以这里选择:do not import setting...不导入设置。

第二步:会让你接受条款,接受即可。

第三步:don't send

第四步:一直下一步(最终选择免费试用30天。)

第五步:可能会让你填写email等信息,这里不填写,继续continue。

第六步:弹出welcome窗口
	点击create new project
	注意:在IDEA当中一个project相当于eclipse当中的一个workspace。

第七步:新建一个Empty Project
	新建一个空的工程,选择创建工程窗口下面“最后的那一项”,Empty Project

第八步:给空的工程起一个名字:javase
	存储到:C:\Users\Administrator\IdeaProjects\javase
	点击finish。

第九步:自动弹出一个每日提示,这个每日提示可以取消掉。以后每一次打开就不再提示了。

第十步:会自动弹出一个:project structure,这个窗口先取消掉。

第十一步:在空的工程下新建Module(模块),IDEA中模块类似于eclipse当中的project。
	eclipse的组织方式:
		workspace--> project
	idea的组织方式:
		project --> module
	
	怎么创建module?
		file菜单-->new --> Module
	
第十二步:在New Module窗口上点击左上角的java,然后next

第十三步:给module起一个名字:chapter15

第十四步:编写代码,在src目录下新建类,写代码,并运行。

3、关于IDEA工具的快捷键以及一些简单的设置

3.1、字体设置
	file --> settings --> 输入font --> 设置字体样式以及字号大小。

3.2、快速生成main方法
	psvm/main

3.3、快速生成System.out.println()
	sout 

3.4、注意:IDEA是自动保存,不需要ctrl + s

3.5、删除一行
	ctrl + y

3.6、怎么运行:
	代码上右键-->run
	或者点击左侧的绿色箭头。
	ctrl + shift + F10

3.7、左侧窗口中的列表怎么展开?怎么关闭?
	左箭头关闭。
	右箭头展开。
	上下箭头移动。

3.8、idea中退出任何窗口,都可以使用esc键盘。(esc就是退出)

3.9、任何新增/新建/添加的快捷键是:
	alt + insert

3.10、窗口变大,变小:
	ctrl + shift + F12

3.11、切换java程序:从HelloWorld切换到User
	alt + 右箭头 
	或者
	alt + 左箭头

3.12、切换窗口:
	alt + 标号
	alt + 1(打开,关闭)
	alt + 2

3.13、提示方法的参数:ctrl + p

3.14、注释:
	单行注释:ctrl + /
	多行注释:ctrl + shift + /

3.15、idea中怎么定位方法/属性/变量?
	光标停到某个单词的下面,这个单词可能是:
		方法名、变量名
	停到单词下面之后,按ctrl键,出现下划线,点击跳转。

3.16、idea当中复制一行是ctrl + d

3.17、idea Mac版 调出setting界面 command + ,

IntelliJ IDEA For Mac 快捷键:
Mac键盘符号和修饰键说明:
⌘ Command
⇧ Shift
⌥ Option
⌃ Control
↩ Return/Enter
⌫ Delete
⌦ 向前删除键(Fn+Delete)
↑ 上箭头
↓ 下箭头
← 左箭头
→ 右箭头
⇞ Page Up(Fn+↑)
⇟ Page Down(Fn+↓)
Home Fn + ←
End Fn + →
⇥ 右制表符(Tab键)
⇤ 左制表符(Shift+Tab)
⎋ Escape (Esc)

一、Editing(编辑)
⌃Space 基本的代码补全(补全任何类、方法、变量)
⌃⇧Space 智能代码补全(过滤器方法列表和变量的预期类型)
⌘⇧↩ 自动结束代码,行末自动添加分号
⌘P 显示方法的参数信息
⌃J, Mid. button click 快速查看文档
⇧F1 查看外部文档(在某些代码上会触发打开浏览器显示相关文档)
⌘+鼠标放在代码上 显示代码简要信息
⌘F1 在错误或警告处显示具体描述信息
⌘N, ⌃↩, ⌃N 生成代码(getter、setter、构造函数、hashCode/equals,toString)
⌃O 覆盖方法(重写父类方法)
⌃I 实现方法(实现接口中的方法)
⌘⌥T 包围代码(使用if…else, try…catch, for, synchronized等包围选中的代码)
⌘/ 注释/取消注释与行注释
⌘⌥/ 注释/取消注释与块注释
⌥↑ 连续选中代码块
⌥↓ 减少当前选中的代码块
⌃⇧Q 显示上下文信息
⌥↩ 显示意向动作和快速修复代码
⌘⌥L 格式化代码
⌃⌥O 优化import
⌃⌥I 自动缩进线
⇥ / ⇧⇥ 缩进代码 / 反缩进代码
⌘X 剪切当前行或选定的块到剪贴板
⌘C 复制当前行或选定的块到剪贴板
⌘V 从剪贴板粘贴
⌘⇧V 从最近的缓冲区粘贴
⌘D 复制当前行或选定的块
⌘⌫ 删除当前行或选定的块的行
⌃⇧J 智能的将代码拼接成一行
⌘↩ 智能的拆分拼接的行
⇧↩ 开始新的一行
⌘⇧U 大小写切换
⌘⇧] / ⌘⇧[ 选择直到代码块结束/开始
⌥⌦ 删除到单词的末尾(⌦键为Fn+Delete)
⌥⌫ 删除到单词的开头
⌘+ / ⌘- 展开 / 折叠代码块
⌘⇧+ 展开所以代码块
⌘⇧- 折叠所有代码块
⌘W 关闭活动的编辑器选项卡

二、Search/Replace(查询/替换)
Double ⇧ 查询任何东西
⌘F 文件内查找
⌘G 查找模式下,向下查找
⌘⇧G 查找模式下,向上查找
⌘R 文件内替换
⌘⇧F 全局查找(根据路径)
⌘⇧R 全局替换(根据路径)
⌘⇧S 查询结构(Ultimate Edition 版专用,需要在Keymap中设置)
⌘⇧M 替换结构(Ultimate Edition 版专用,需要在Keymap中设置)

三、Usage Search(使用查询)
⌥F7 / ⌘F7 在文件中查找用法 / 在类中查找用法
⌘⇧F7 在文件中突出显示的用法
⌘⌥F7 显示用法
⌘⇧I 查看定义的类,快速查看

四、Compile and Run(编译和运行)
⌘F9 编译Project
⌘⇧F9 编译选择的文件、包或模块
⌃⌥R 弹出 Run 的可选择菜单
⌃⌥D 弹出 Debug 的可选择菜单
⌃R 运行
⌃D 调试
⌃⇧R, ⌃⇧D 从编辑器运行上下文环境配置

五、Debugging(调试)
F8 进入下一步,如果当前行断点是一个方法,则不进入当前方法体内
F7 进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中
⇧F7 智能步入,断点所在行上有多个方法调用,会弹出进入哪个方法
⇧F8 跳出
⌥F9 运行到光标处,如果光标前有其他断点会进入到该断点
⌥F8 计算表达式(可以更改变量值使其生效)
⌘⌥R 恢复程序运行,如果该断点下面代码还有断点则停在下一个断点上
⌘F8 切换断点(若光标当前行有断点则取消断点,没有则加上断点)
⌘⇧F8 查看断点信息

六、Navigation(导航)
⌘O 查找类文件
⌘⇧O 查找所有类型文件、打开文件、打开目录,打开目录需要在输入的内容前面或后面加一个反斜杠/
⌘⌥O 前往指定的变量 / 方法
⌃← / ⌃→ 左右切换打开的编辑tab页
F12 返回到前一个工具窗口
⎋ 从工具窗口进入代码文件窗口
⇧⎋ 隐藏当前或最后一个活动的窗口,且光标进入代码文件窗口
⌘⇧F4 关闭活动run/messages/find/… tab
⌘L 在当前文件跳转到某一行的指定处
⌘E 显示最近打开的文件记录列表
⌘⌥← / ⌘⌥→ 退回 / 前进到上一个操作的地方
⌘⇧⌫ 跳转到最后一个编辑的地方
⌥F1 显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择(如在代码编辑窗口可以选择显示该文件的Finder)
⌘B / ⌘ 鼠标点击 进入光标所在的方法/变量的接口或是定义处
⌘⌥B 跳转到实现处,在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
⌥ Space, ⌘Y 快速打开光标所在方法、类的定义
⌃⇧B 跳转到类型声明处
⌘U 前往当前光标所在方法的父类的方法 / 接口定义
⌃↓ / ⌃↑ 当前光标跳转到当前文件的前一个/后一个方法名位置
⌘] / ⌘[ 移动光标到当前所在代码的花括号开始/结束位置
⌘F12 弹出当前文件结构层,可以在弹出的层上直接输入进行筛选(可用于搜索类中的方法)
⌃H 显示当前类的层次结构
⌘⇧H 显示方法层次结构
⌃⌥H 显示调用层次结构
F2 / ⇧F2 跳转到下一个/上一个突出错误或警告的位置
F4 / ⌘↓ 编辑/查看代码源
⌥ Home 显示到当前文件的导航条
F3选中文件/文件夹/代码行,添加/取消书签
⌥F3 选中文件/文件夹/代码行,使用助记符添加/取消书签
⌃0…⌃9 定位到对应数值的书签位置
⌘F3 显示所有书签

七、Refactoring(重构)
F5 复制文件到指定目录
F6 移动文件到指定目录
⌘⌫ 在文件上为安全删除文件,弹出确认框
⇧F6 重命名文件
⌘F6 更改签名
⌘⌥N 一致性
⌘⌥M 将选中的代码提取为方法
⌘⌥V 提取变量
⌘⌥F 提取字段
⌘⌥C 提取常量
⌘⌥P 提取参数

八、VCS/Local History(版本控制/本地历史记录)
⌘K 提交代码到版本控制器
⌘T 从版本控制器更新代码
⌥⇧C 查看最近的变更记录
⌃C 快速弹出版本控制器操作面板

九、Live Templates(动态代码模板)
⌘⌥J 弹出模板选择窗口,将选定的代码使用动态模板包住
⌘J 插入自定义动态代码模板

十、General(通用)
⌘1…⌘9 打开相应编号的工具窗口
⌘S 保存所有
⌘⌥Y 同步、刷新
⌃⌘F 切换全屏模式
⌘⇧F12 切换最大化编辑器
⌥⇧F 添加到收藏夹
⌥⇧I 检查当前文件与当前的配置文件
§⌃, ⌃` 快速切换当前的scheme(切换主题、代码样式等)
⌘, 打开IDEA系统设置
⌘; 打开项目结构对话框
⇧⌘A 查找动作(可设置相关选项)
⌃⇥ 编辑窗口标签和工具窗口之间切换(如果在切换的过程加按上delete,则是关闭对应选中的窗口)

3、抽象类和接口以及抽象类和接口的区别。

抽象类的基础语法:

1、什么是抽象类?
类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。
类本身是不存在的,所以抽象类无法创建对象【无法实例化】。

2、抽象类属于什么类型?
抽象类也属于引用数据类型。

3、抽象类怎么定义?
语法:

[修饰符列表] abstract class 类名{
	类体;
}

4、抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。

5、final和abstract不能联合使用,这两个关键字是对立的。

6、抽象类的子类可以是抽象类。

7、抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。

8、抽象类关联到一个概念:抽象方法。什么是抽象方法呢?
抽象方法表示没有实现的方法,没有方法体的方法。例如:

public abstract void doSome();

抽象方法的特点是:
特点一:没有方法体,以分号结尾。
特点二:前面修饰符列表中有abstract关键字。

9、抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中。

10、重要结论:
一个非抽象的类继承抽象类,必须将抽象类中的抽象方法实现了。
这是java语法上强行规定的,必须的,不然编译器就报错了。

这里的覆盖或者说重写,也可以叫做实现。(对抽象的实现。)

	面试题(判断题):java语言中凡是没有方法体的方法都是抽象方法。
		不对,错误的。
		Object类中就有很多方法都没有方法体,都是以“;”结尾的,但他们
		都不是抽象方法,例如:
			public native int hashCode();
			这个方法底层调用了C++写的动态链接库程序。
			前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。

接口的基础语法:

1、接口是一种“引用数据类型”。编译之后也是一个class字节码文件。

2、接口是完全抽象的。(抽象类是半抽象的)或者也可以说接口是特殊的抽象类。

3、接口怎么定义:

[修饰符列表] interface 接口名{

}

4、接口支持多继承,一个接口可以继承多个接口。

5、接口中只有常量+抽象方法。

6、接口中所有的元素都是public修饰的。(都是公开的)

7、接口中抽象方法的public abstract可以省略。

8、接口中常量的public static final可以省略。

9、接口中方法不能有方法体。

10、一个非抽象的类,实现接口的时候,必须将接口中所有方法加以实现。

11、一个类可以实现多个接口。

12、extends和implements可以共存,extends在前,implements在后。

13、使用接口,写代码的时候,可以使用多态(父类型引用指向子类型对象)。

接口在开发中的作用:

注意:接口在开发中的作用,类似于多态在开发中的作用。

多态:面向抽象编程,不要面向具体编程。降低程序的耦合度。提高程序的扩展力。

public class Master{
	public void feed(Dog d){}
	public void feed(Cat c){}
	//假设又要养其它的宠物,那么这个时候需要再加1个方法。(需要修改代码了)
	//这样扩展力太差了,违背了OCP原则(对扩展开放,对修改关闭。)
}
			
public class Master{
	public void feed(Animal a){
	// 面向Animal父类编程,父类是比子类更抽象的。
	//所以我们叫做面向抽象编程,不要面向具体编程。
	//这样程序的扩展力就强。
	}
}
		

接口在开发中的作用?
接口是不是完全的?是。
而我们以后正好要求,面向抽象编程。
面向抽象编程这句话以后可以修改为:面向接口编程。
有了接口就有了可插拔。可插拔表示扩展力很强。不是焊接死的。

		主板和内存条之间有插槽,这个插槽就是接口,内存条坏了,可以重新
		买一个换下来。这叫做高扩展性。(低耦合度。)

		接口在现实世界中是不是到处都是呢?
			螺栓和螺母之间有接口
			灯泡和灯口之间有接口
			笔记本电脑和键盘之间有接口(usb接口,usb接口是不是某个计算机协会制定的协议/规范。)
			接口有什么用?扩展性好。可插拔。
			接口是一个抽象的概念。
		
		分析:
			中午去饭馆吃饭,这个过程中有接口吗?

				接口是抽象的。	

				菜单是一个接口。(菜单上有一个抽象的照片:西红柿炒鸡蛋)

				谁面向接口调用。(顾客面向菜单点菜,调用接口。)

				谁负责实现这个接口。(后台的厨师负责把西红柿鸡蛋做好!是接口的实现者。)

				这个接口有什么用呢?
					这个饭馆的“菜单”,让“顾客”和“后厨”解耦合了。
					顾客不用找后厨,后厨不用找顾客。他们之间完全依靠这个抽象的菜单沟通。
		
		总结一句话:三个字“解耦合”
			面向接口编程,可以降低程序的耦合度,提高程序的扩展力。符合OCP开发原则。
			接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度。)

			接口可以解耦合,解开的是谁和谁的耦合!!!
			任何一个接口都有调用者和实现者。
			接口可以将调用者和实现者解耦合。
			调用者面向接口调用。
			实现者面向接口编写实现。

			以后进行大项目的开发,一般都是将项目分离成一个模块一个模块的,
			模块和模块之间采用接口衔接。降低耦合度。

类型和类型之间的关系:

	is a(继承)、has a(关联)、like a(实现)

		is a:
			Cat is a Animal(猫是一个动物)
			凡是能够满足is a的表示“继承关系”
			A extends B

		has a:
			I has a Pen(我有一支笔)
			凡是能够满足has a关系的表示“关联关系”
			关联关系通常以“属性”的形式存在。
			A{
				B b;
			}
		
		like a:
			Cooker like a FoodMenu(厨师像一个菜单一样)
			凡是能够满足like a关系的表示“实现关系”
			实现关系通常是:类实现接口。
			A implements B

抽象类和接口有什么区别?

	在这里我们只说一下抽象类和接口在语法上的区别。
	至于以后抽象类和接口应该怎么进行选择,通过后面的项目去体会/学习。

	抽象类是半抽象的。
	接口是完全抽象的。

	抽象类中有构造方法。
	接口中没有构造方法。

	接口和接口之间支持多继承。
	类和类之间只能单继承。

	一个类可以同时实现多个接口。
	一个抽象类只能继承一个类(单继承)。

	接口中只允许出现常量和抽象方法。
	
	这里先透露一个信息:
		以后接口使用的比抽象类多。一般抽象类使用的还是少。
		接口一般都是对“行为”的抽象。

package和import

package
	第一:package出现在java源文件第一行。
	第二:带有包名怎么编译?javac -d . xxx.java
	第三:怎么运行?java 完整类名

	补充:以后说类名的时候,如果带着包名描述,表示完整类名。
	如果没有带包,描述的话,表示简类名。
		java.util.Scanner 完整类名。
		Scanner 简类名

import
	import什么时候不需要?
		java.lang不需要。
		同包下不需要。 
		其它一律都需要。

	怎么用?

import语句只能出现在package语句之下,class声明语句之上。
import 完整类名;
import 包名.*;

		import java.util.Scanner; // 完整类名。

		// 同学的疑问:这样是不是效率比较低。
		// 这个效率不低,因为编译器在编译的时候,会自动把*变成具体的类名。
		import java.util.*;

		// 想省懒劲你不能太省了。
		import java.*; 这是不允许的,因为在java语言中规定,这里的*只代表某些类的名字。(一个包中的全部类)

JDK类库的根类:Object

这个老祖宗类中的方法我们需要先研究一下,因为这些方法都是所有子类通用的。
任何一个类默认继承Object。就算没有直接继承,最终也会间接继承。

Object类当中有哪些常用的方法?
	我们去哪里找这些方法呢?
		第一种方法:去源代码当中。(但是这种方式比较麻烦,源代码也比较难)
		第二种方法:去查阅java的类库的帮助文档。

	什么是API?
		应用程序编程接口。(Application Program Interface)
		整个JDK的类库就是一个javase的API。
		每一个API都会配置一套API帮助文档。
		SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)
	
	目前为止我们只需要知道这几个方法即可:
		protected Object clone()     // 负责对象克隆的。
		int hashCode()	          // 获取对象哈希值的一个方法。
		boolean equals(Object obj)  // 判断两个对象是否相等
		String toString()            // 将对象转换成字符串形式
		protected void finalize()     // 垃圾回收器负责调用的方法

关于Object类中的toString方法:

1、源代码长什么样?

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

源代码上toString方法的默认实现是:
类名@对象的内存地址转换为十六进制的形式

2、sun公司设计toString()方法的目的是什么?toString()方法的作用是什么?
通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”

3、其实sun公司开发java语言的时候,建议所有的子类都去重写toString()方法。toString方法应该是一个简洁的、详实的、易阅读的。

toString()方法
以后所有类的toString()方法是需要重写的。
重写规则,越简单越明了就好。

System.out.println(引用); 这里会自动调用“引用”的toString()方法。

String类是SUN写的,toString方法已经重写了。

关于Object类中的equals()方法:

1、equals()方法的源代码:

public boolean equals( Object obj){
	return (this == obj);
}

以上这个方法是Object类的默认实现。

2、sun公司设计equals方法的目的是?
以后编程的过程当中,都要通过equals方法来判断两个对象是否相等。
equals方法是判断两个对象是否相等。

3、我们需要研究一下Object类给的这个默认的equals方法够不够用!!!
在Object类中的equals方法当中,默认采用的是“== ”判断两个java对象是否相等。而“==”判断的是两个java对象的内存地址,我们应该判断两个java对象的内容是否相等。所以老祖宗的equals方法不够用,需要子类重写equals。

4、判断两个java对象是否相等,不能使用“== ”,因为“==”比较的是两个对象的内存地址。

equals()方法
	以后所有类的equals方法也需要重写,因为Object中的equals方法比较的是两个对象的内存地址,我们应该比较内容,所以需要重写。

	重写规则:自己定,主要看是什么和什么相等时表示两个对象相等。

	基本数据类型比较实用:==

对象和对象比较:调用equals方法

	String类是SUN编写的,所以String类的equals方法重写了。
	以后判断两个字符串是否相等,最好不要使用==,要调用字符串对象的equals方法。

	注意:重写equals方法的时候要彻底。

关于Object类中的finalize()方法(非重点):

1、在Object类中的源代码:

protected void finalize() throws Throwable { }

2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。

3、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。不像equals toString,是需要写代码调用的。finalize()只需要重写,重写完将来自动会有程序来调用。

3、finalize()方法的执行时机:
当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法。

4、finalize()方法实际上是sun公司为java程序员准备的一个时机,垃圾销毁时机。如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。

5、静态代码块的作用是什么?

static{
	......
}

静态代码块在类加载时刻执行,并且只执行一次。
这是一个sun准备的类加载时机。

finalize()方法同样也是sun为程序员准备的一个时机。
这个时机是垃圾回收时机

6、提示:
java中的垃圾回收器不是轻易启动的,垃圾太少,或者时间没到,种种条件下,有可能启动,也有可能不启动。

finalize()方法
这个方法是protected修饰的,在Object类中这个方法的源代码是?

protected void finalize() throws Throwable { }

关于Object类中的hashCode方法:

1、源代码:

public native int hashCode();

这个方法不是抽象方法,带有native关键字,底层调用c++程序。

hashCode()方法返回的是哈希码:
实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值。所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址。

匿名内部类

1、什么是内部类?
内部类:在类的内部又定义了一个新的类。

2、内部类的分类:
静态内部类:类似于静态变量
1、静态内部类中可以直接访问外部类的静态成员,如果要访问外部类的实例成员,需要通过外部类的实例去访问。
2、静态内部类的实例化方式
A.B a = new A.B( );
3、静态内部类中可以定义静态成员,也可以定义实例成员。
4、可以通过类名直接调用静态内部类中的静态成员。

实例内部类:类似于实例变量
1、实例内部类的实例化方式要依靠外部类的实例来创建
C c = new A( ).new C( );
相当于
A a = new A( ); A.C c = a.new C( );
2、实例内部类中不能够定义静态成员。
3、如果实例内部类C中和外部类A中有同名的参数,则就近原则 this.ai 代表C的 A.this.ai代表A的。
4、实例内部类中可以访问到外部类的所有成员。
5、每一个实例内部类的实例都只对应一个外部类的实例,一个外部类的实例可以对应多个内部类的实例。

局部内部类:类似于局部变量
1、局部内部类不能够使用权限修饰符(public private protected)以及static
2、局部内部类中不可以定义静态变量
3、局部内部类中可以访问到外部类的所有成员,可以访问到外部类的final修饰的变量
4、局部内部类的作用范围在当前方法内,如果要是使用必须声明在类定义之下,外部类无法创建局部内部类的实例
匿名内部类
可能是在实际应用中接触最多的一个内部类

1、匿名内部类的使用方法,new接口/抽象类( ) { 实现其中未实现的方法 }

2、匿名内部类是唯一一个没有构造器的类。

3、匿名内部类不可以拥有静态成员。

4、可以访问外部类的所有成员。

5、一般用作放在方法的参数中,只使用一次的那种。

6、使用内部类编写的代码,可读性很差,能不用尽量不用。

7、匿名内部类是局部内部类的一种。
因为这个类没有名字而得名,叫做匿名内部类。

8、学习匿名内部类主要是让大家以后在阅读别人代码的时候,能够理解。并不代表以后都要这样写。因为匿名内部类有两个缺点:
缺点1:太复杂,太乱,可读性差。
缺点2:类没有名字,以后想重复使用,不能用。

数组

1、java语言中的数组是一种引用数据类型。不属于基本数据类型。数组的父类是Object。

2、数组实际上是一个容器,可以同时容纳多个元素。(数组是一组数据的集合)
数组:字面意思是:“一组数据”

3、数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据。

4、数组因为是引用类型,所以数组对象是堆内存当中的。(数组是存储在堆当中的)

5、数组当中如果存储的是“java对象”的话,实际上存储的是对象的“引用(内存地址)”

6、数组一旦创建,在java中规定,长度不可变。(数组长度不可变)

7、数组的分类:一维数组、二维数组、三维数组、多维数组。。。(一维数组较多,二维数组偶尔使用!)

8、所有的数组对象都有length属性(java自带的),用来获取数组中元素的个数。

9、java中的数组要求数组中元素的类型统一。比如int类型数组只能存储int类型,Person类型数组只能存储Person类型。

10、数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排列的)是连续的。内存地址连续这是数组存储元素的特点。数组实际上是一种简单的数据结构。

11、所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象的内存地址)

12、数组中每一个元素都是有下标的,下标从0开始,以1递增。最后一个元素的下标是:length - 1。

13、数组的优缺点。
优点
查询/查找/检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构。
为什么检索效率高?
第一:每一个对象的内存地址在空间存储上是连续的。
第二:每一个元素类型相同,所以占用空间大小一样。
第三:知道第一个元素的内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率是最高的。

数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个内存地址,直接定位的)

缺点:
第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作。
第二:数组不能存储大数据量,为什么?
因为很难在内存空间上找到一块特别大的连续的空间。

注意:对于数组中最后一个元素的增删,是没有效率影响的。

14、怎么声明/定义一个一维数组?
语法格式:

int [ ] array1;
double [ ] array2;
boolean [ ] array3;
String [ ] array4;
Object [ ] array5;

15、怎么初始化一个一维数组呢?
包括两种方式:静态初始化一维数组,动态初始化一维数组。
静态初始化语法格式:

int [ ] array = { 100 , 2100 , 300 , 55 };

动态初始化语法格式:

int [ ] array = new int [5];  // 这里的5表示数组的元素个数。
                              // 初始化一个5个长度的int类型数组,每个元素默认值0
String [ ] names = new String[6]; // 初始化6个长度的String类型数组,每个元素默认值null。

什么时候采用静态初始化方式,什么时候采用动态初始化方式呢?
当创建数组的时候,确定数组中存储哪些具体元素时,采用静态初始化方式。
当创建数组的时候,不确定将来数组中存储哪些数据,可以采用动态初始化的方式,预先分配内存空间。

16、关于一维数组的扩容。

在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
数组满了,需要扩容。
java中对数组的扩容是:
先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。

结论:数组扩容效率较低。因为涉及到数组的拷贝(调用JDK System类中的arraycopy方法,来完成数组的拷贝)的问题。所以在以后的开发中请注意:尽可能少的进行数组的拷贝。可以在创建数组对象的时候预估计以下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率。

关于java中的二维数组

1、二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。

2、三维数组是什么?
三维数组是一个特殊的二维数组,特殊在这个二维数组中每一个元素都是一个一维数组。实际开发中使用最多的就是一维数组。二维数组也很少使用。三维数组几乎不用。

3、二维数组静态初始化和动态初始化
静态初始化:

int[][] array = {{1,1,1},{2,3,4,5},{0,0,0,0}};
Object[][] array = {{new Object() , new Object()},{new Object() , new Object()}};

动态初始化:

int[][] array = new int[3][4];
Object[][] array = new Object[4][4];

4、二维数组的遍历

for(int i = 0, i < array.length, i++){  // 外层for循环负责遍历外面的一维数组
	// 里面的for循环负责遍历二维数组里面的一维数组
	for(int j = 0, j < array[i].length, j++){
		System.out.print(array[i][j]);
	}
	// 换行
	System.out.println();
}

常见的算法:

	排序算法:
		冒泡排序算法
		选择排序算法

	查找算法:
		二分法查找
	
	以上算法在以后的java实际开发中我们不需要使用的。
	因为java已经封装好了,直接调用就行。
	只不过以后面试的时候,可能会有机会碰上。

算法实际上在java中不需要精通,因为java中已经封装好了,
要排序就调用方法就行。例如:java中提供了一个数组工具类:
	java.util.Arrays
		Arrays是一个工具类。
		其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。

冒泡排序:

参与比较的数据:9 8 10 7 6 0 11
第1次循环:
8 9 10 7 6 0 11 (第1次比较:交换)
8 9 10 7 6 0 11 (第2次比较:不交换)
8 9 7 10 6 0 11 (第3次比较:交换)
8 9 7 6 10 0 11 (第4次比较:交换)
8 9 7 6 0 10 11 (第5次比较:交换)
8 9 7 6 0 10 11 (第6次比较:不交换)
最终冒出的最大数据在右边:11

参与比较的数据:8 9 7 6 0 10
第2次循环:
8 9 7 6 0 10(第1次比较:不交换)
8 7 9 6 0 10(第2次比较:交换)
8 7 6 9 0 10(第3次比较:交换)
8 7 6 0 9 10(第4次比较:交换)
8 7 6 0 9 10(第5次比较:不交换)

参与比较的数据:8 7 6 0 9
第3次循环:
7 8 6 0 9(第1次比较:交换)
7 6 8 0 9(第2次比较:交换)
7 6 0 8 9(第3次比较:交换)
7 6 0 8 9(第4次比较:不交换)

参与比较的数据:7 6 0 8
第4次循环:
6 7 0 8(第1次比较:交换)
6 0 7 8(第2次比较:交换)
6 0 7 8(第3次比较:不交换)

参与比较的数据:6 0 7
第5次循环:
0 6 7(第1次比较:交换)
0 6 7(第2次比较:不交换)

参与比较的数据:0 6
第6次循环:
0 6 (第1次比较:不交换)

for(int i = 6; i > 0; i--){ // 6次
	//7条数据比6次
	//6条数据比5次
	//5条数据比4次
	//4条数据比3次
	//3条数据比2次
	//2条数据比1次
	for(int j = 0; j < i; j++){
	
	}
}

选择排序:

选择排序比冒泡排序的效率高。
高在交换位置的次数上。
选择排序的交换位置是有意义的。

循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和
最前面的数据“交换位置”。


参与比较的数据:3 1 6 2 5 (这一堆参加比较的数据中最左边的元素下标是0)
第1次循环之后的结果是:
1 3 6 2 5 

参与比较的数据:3 6 2 5 (这一堆参加比较的数据中最左边的元素下标是1)
第2次循环之后的结果是:
2 6 3 5 

参与比较的数据:6 3 5 (这一堆参加比较的数据中最左边的元素下标是2)
第3次循环之后的结果是:
3 6 5 

参与比较的数据:6 5 (这一堆参加比较的数据中最左边的元素下标是3)
第4次循环之后的结果是:
5 6

注意:5条数据,循环4次。

二分法查找:

第一:二分法查找建立在排序的基础之上。
第二:二分法查找效率要高于“一个挨着一个”的这种查找方式。
第三:二分法查找原理?
10(0下标) 23 56 89 100 111 222 235 500 600(下标9)arr数组

目标:找出600的下标
(0 + 9)/ 2 --> 4(中间元素的下标)

arr[4]这个元素就是中间元素:arr[4]是100
100 < 600
说明被查找的元素在100的右边。
那么此时开始下标变成:4+1

(5 + 9)/ 2 --> 7(中间元素的下标)
arr[7] 对应的是:235
235 < 600
说明被查找的元素在235的右边。

开始下标又进行了转变:7 + 1
(8 + 9)/ 2 --> 8
arr[8] -->500
500 < 600
开始元素的下标又发生了变化:8 + 1
(9 + 9)/ 2 --> 9
arr[9]是600,正好和600相等,此时找到了。

常用类:

关于java jdk中内置的一个类-------java.lang.String

1、String表示字符串类型,属于引用数据类型,不属于基本数据类型。

2、在java中随便使用双引号括起来的都是String对象。例如:“abc”,“def”,“hello world”,这是三个String对象。

3、java中规定,双引号括起来的字符串,是不可变的,也就是说"abc"自出生到最终死亡,不可变,不能变成"abcd",也不能

4、在jdk当中双引号括起来的字符串,例如:“abc”,"def"都是直接存储在"方法区"的"字符串常量池"当中的。

为什么sun公司字符串存储在一个"字符串常量池"当中呢?
因为字符串在实际的开发中使用太频繁。为了执行效率,所以把字符串放到了方法区的字符串常量池当中。

关于String类中的构造方法

  • 1、String s = new String("");
  • 2、String s = “”; 最常用
  • 3、String s = new String(char数组);
  • 4、String s = new String(char数组,起始下标,长度);
  • 5、String s = new String(byte数组);
  • 6、String s = new String(byte数组,起始下标,长度);

String类当中常用方法。

  1. endsWith:判断字符串是否以指定的后缀结束
  2. startsWith,判断字符串是否以指定的前缀开始
  3. equals,字符串相等比较,不忽略大小写
  4. equalsIgnoreCase,字符串相等比较,忽略大小写
  5. indexOf,取得指定字符在字符串的位置
  6. lastIndexOf,返回最后一次字符串出现的位置
  7. length,取得字符串的长度
  8. replaceAll,替换字符串中指定的内容
  9. split,根据指定的表达式拆分字符串
  10. substring,截子串
  11. trim,去前尾空格
  12. valueOf,将其他类型转换成字符串
		/*
         1(掌握)、char charAt(int index)
         */
        char c = "中国人".charAt(1); // "中国人"是一个字符串String对象,只要是对象就能"点."
        System.out.println(c); // 国
        /*
          2(了解)、int compareTo(String anotherString)
         */
        int result = "abc".compareTo("abc");
        System.out.println(result);// 0(等于0)前后一致

        int result2 = "abcd".compareTo("abce");
        System.out.println(result2);// -1(小于0)前小后大

        int result3 = "abce".compareTo("abcd");
        System.out.println(result3);// 1(大于0)前大后小

        // 拿着字符串第一个字母和后面字符串的第一个字母比较。能分胜负就不再比较了。
        System.out.println("xyz".compareTo("yxz"));// -1

        /*
        3(掌握).boolean contains(CharSequence s)
         */
        // 判断前面的字符串中是否包含后面的子字符串。
        System.out.println("HelloWorld.java".contains(".java"));// true
        System.out.println("http://www.baidu.com".contains("https://"));// false

        /*
        4(掌握).boolean endsWith(String suffix)
         */
        // 判断当前字符串是否以某个字符串结尾。
        System.out.println("test.txt".endsWith(".java"));// false
        System.out.println("test.txt".endsWith(".txt"));// true
        System.out.println("jbcioiusoo".endsWith("oo"));// true

        /*
        5(掌握).boolean equals(Object anObject)
         */
        // 比较两个字符串必须使用equals方法,不能使用"=="
        // equals方法有没有调用compareTo方法?
        System.out.println("abc".equals("abc"));// true

        /*
        6(掌握).boolean equalsIgnoreCase(String anotherString)
         */
        // 判断两个字符串是否相等,并且同时忽略大小写。
        System.out.println("ABc".equalsIgnoreCase("abC"));// true

        /*
        7(掌握).byte[] getBytes()
         */
        // 将字符串对象转换成字节数组
        byte[] bytes = "abcdef".getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.println(bytes[i]);
        }

        /*
        8(掌握).int indexOf(String str)
         */
        // 判断某个字符串在当前字符串中第一次出现处的索引(下标)。
        System.out.println("oraclejavac++.netc#phppythonjavaoraclec++".indexOf("java"));// 6

        /*
        9(掌握).boolean isEmpty()
         */
        // 判断某个字符串是否为"空字符串"。底层源代码调用的应该是字符串的length()方法。
        String s = "";
        System.out.println(s.isEmpty());// true

        /*
        10(掌握).int length()
         */
        // 面试题:判断数组长度和判断字符串长度不一样
        // 判断数组长度是length属性,判断字符串长度是length()方法。
        System.out.println("abc".length());// 3
        System.out.println("".length());// 0

        /*
        11(掌握).int lastIndexOf(String str)
         */
        // 判断某个子字符串在当前字符串当中最后一次出现的索引(下标)。
        System.out.println("oraclejavac++javac#phpjavapython".lastIndexOf("java"));// 22

        /*
        12(掌握).String replace(CharSequence target, CharSequence replacement)
         */
        // 替换。
        // String的父接口就是:CharSequence
        String newString = "http://www.baidu.com".replace("http://", "https://");
        System.out.println(newString);// https://www.baidu.com
        // 把以下字符串中的"="替换成":"
        String newString2 = "name=zhangsan&password=123&age=20".replace("=", ":");
        System.out.println(newString2);

        /*
        13(掌握).String[] split(String regex)
         */
        // 拆分字符串
        String[] ymd = "1980-10-11".split("-");// "1980-10-11"以"-"分隔符进行拆分。
        for (int i = 0; i < ymd.length; i++) {
            System.out.println(ymd[i]);// 1980 10 11
        }
        String param = "name=zhangsan&password=123&age=20";
        String[] params = param.split("&");
        for (int i = 0; i < params.length; i++) {
            System.out.println(params[i]);// name=zhangsan password=123 age=20
        }

        /*
        14(掌握).boolean startsWith(String prefix)
         */
        // 判断某个字符串是否以某个子字符串开始。
        System.out.println("http://www.baidu.com".startsWith("http"));// true
        System.out.println("http://www.baidu.com".startsWith("https"));// false

        /*
        15(掌握).String substring(int beginIndex) 参数是起始下标。
         */
        // 截取字符串
        System.out.println("http://www.baidu.com".substring(7));// www.baidu.com

        /*
        16(掌握).String substring(int beginIndex, int endIndex)
         */
        // beginIndex起始位置(包括)
        // endIndex结束位置(不包括)
        System.out.println("http://www.baidu.com".substring(7, 10));// www

        /*
        17(掌握).char[] toCharArray()
         */
        // 将字符串转换成char数组
        char[] chars = "我是中国人".toCharArray();
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }

        /*
        18(掌握).String toLowerCase()
         */
        // 转换为小写。
        System.out.println("ABCDefKXyz".toLowerCase());

        /*
        19(掌握).String toUpperCase();
         */
        // 转换为大写。
        System.out.println("ABCDefKXyz".toUpperCase());

        /*
        20(掌握).String trim();
         */
        // 去除字符串前后空白
        System.out.println("    hello   world   ".trim());

        /*
        21(掌握).String中只有一个方法是静态的,不需要new对象
         */
        // 这个方法叫做valueOf
        // 作用:将"非字符串"转换成"字符串"
        // String s1 = String.valueOf(true);
        // String s1 = String.valueOf(100);
        // String s1 = String.valueOf(3.14);

        // 这个静态的valueOf方法,参数是一个对象的时候,会自动调用该对象的toString()方法吗?
        String s1 = String.valueOf(new Customer());
        // System.out.println(s1); // 没有重写toString()方法之前是对象内存地址
        System.out.println(s1);// 我是一个VIP客户!
    }
}
class Customer {
    // 重写toString方法
    @Override
    public String toString() {
        return "我是一个VIP客户!";
    }
}

思考:我们在实际的开发中,如果需要进行字符串的频繁拼接,会有什么问题?

  • 因为java中的字符串是不可变的,每一次拼接都会产生新字符串。
  • 这样会占用大量的方法区内存。造成内存空间的浪费。
  • String s = “abc”;
  • s += “hello”;
  • 就以上两行代码,就导致在方法区字符串常量池当中创建了3个对象:
  • “abc”
  • “hello”
  • “abchello”

如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的:

  • java.lang.StringBuffer
  • java.lang.StringBuilder
    拼接字符串,以后拼接字符串统一调用append()方法。
    append是追加的意思。

如何优化StringBuffer的性能?

  • 在创建StringBuffer的时候尽可能给定一个初始化容量。
  • 最好减少底层数组的扩容次数。预估计一下,给一个大一些初始化容量。
  • 关键点:给一个合适的初始化容量。可以提高程序的执行效率。

1、面试题:String为什么是不可变的?
我看过源代码,String类中有一个Char[]数组,这个Char[]数组采用了final修饰,因为数组一旦创建长度不可变。并且被final修饰的引用一旦指向某个对象之后,不可再指向其他对象,所以String是不可变的!“abc"无法变成"abcd”

2、StringBuilder和StringBuffer为什么是可变的呢?
我看过源代码,StringBuffer/StringBuilder内部实际上是个byte[]数组,这个byte[]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量我记得应该是16,当存满之后会进行扩容,底层调用了数组拷贝的方法System.arraycopy()…是这样扩容的。所以StringBuilder/StringBuffer适合于使用字符串的频繁拼接操作。

3、StringBuffer和StringBuilder的区别?
StringBuffer中的方法都有:synchronized关键字修饰。表示StringBuffer在多线程环境下运行是安全的。
StringBuilder中的方法都没有:synchronized关键字修饰。表示StringBuilder在多线程环境下运行是不安全的。
StringBuffer是线程安全的。
StringBuilder是非线程安全的。

包装类

1、8种基本数据类型对应的包装类型名是什么?
基本数据类型 包装类型

byte java.lang.Byte(父类Number)
short java.lang.Short(父类Number)
int java.lang.Integer(父类Number)
long java.lang.Long(父类Number)
float java.lang.Float(父类Number)
double java.lang.Double(父类Number)
boolean java.lang.Boolean(父类Object)
char java.lang.Character(父类Object)

2、以上八种包装类中,重点以java.lang.Integer为代表进行学习,其他的类型照葫芦画瓢就行。

3、八种包装类中其中6个都是数字对应的包装类,他们的父类都是Number,可以先研究一下Number中公共的方法:
Number是一个抽象类,无法实例化对象。
Number类中有这样的方法:
byte byteValue() 以byte形式返回指定的数值。
abstract double doubleValue() 以double形式返回指定的数值。
abstract float floatValue() 以float形式返回指定的数值。
abstract int intValue() 以int形式返回指定的数值。
abstract long longValue() 以long形式返回指定的数值。
short shortValue() 以short形式返回指定的数值。
这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的。

在java5之后,引入了一种新特性,自动装箱和自动拆箱

  • 自动装箱:基本数据类型自动转换成包装类。
  • 自动拆箱:包装类自动转换成基本数据类型。

java中为了提高程序的执行效率,将[-128到127]之间所有的包装对象提前创建好,放到了一个方法区的"整数型常量池"当中了,目的是只要用这个区间的数据不需要再new了,直接从整数型常量池中取出来。

重点方法:
static int parseInt(String s)
静态方法,传参String,返回int
网页上文本框中输入的100实际上是"100"字符串。后台数据库中要求存储100数字,此时java程序需要将"100"转换成100数字。

int retValue = Integer.parseInt("123"); // String -转换-> int

日期类
1、获取系统当前时间
Date d = new Date();

2、日期格式化:Date --> String
yyyy 年
MM 月
dd 日
HH 时
mm 分
ss 秒
SSS 毫秒(毫秒3位,最高999。1000毫秒代表1秒)
注意:在日期格式中,除了y M d H m s S这些字符不能随便写之外,剩下的符号格式随意组织。

yyyy-MM-dd HH:mm:ss SSS
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss SSS”);
String s = sdf.format(new Date());

3、String --> Date
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
Date d = sdf.parse(“2008-08-08 08:08:08”);

4、获取毫秒数
// 获取自1970年1月1日 00:00:00:000到当前系统时间的总毫秒数。
1秒 = 1000毫秒
long begin = System.currentTimeMillis();
Date d = new Date(begin - 1000 * 60 * 60 * 24);

简单总结一下System类的相关属性和方法:
System.out 【out是System类的静态变量】
System.out.println() 【println()方法不是System类的,是printStream类的方法】
System.gc() 建议启动垃圾回收器
System.currentTimeMillis() 获取自1970年1月1日到系统当前时间的总毫秒数
System.exit(0) 退出JVM

数字类
1、DecimalFormat数字格式化
###,###.## 表示加入千分位,保留两个小数。
###,###.0000 表示加入千分位,保留4个小数,不够补0

2、BigDecimal
BigDecimal 属于大数据,精度极高。不属于基本数据类型,属于java对象(引用数据类型)
这是sun提供的一个类,专门用在财务软件当中。

注意:财务软件中double是不够用的。
财务软件中通常使用BigDecimal

随机数
1、怎么产生int类型随机数。

Random r = new Random();
int i = r.nextInt();

2、怎么产生某个范围之内的int类型随机数。

Random r = new Random();
int i = r.nextInt(101); // 产生[0-100]的随机数。

枚举
1、枚举是一种引用数据类型。

2、枚举编译之后也是class文件。

3、枚举类型怎么定义?

enum 枚举类型名{
		枚举值,枚举值2,枚举值3
}

4、当一个方法执行结果超过两种情况,并且是一枚一枚可以列举出来
的时候,建议返回值类型设计为枚举类型。

你可能感兴趣的:(Java开发,java)