计算机基础知识
一、快捷键
- Ctrl+C:复制
- Ctrl+V:粘贴
- Ctrl+A:全选
- Ctrl+X:剪切
- Ctrl+Z:撤销
- Ctrl+S:保存
- Alt+F4:关闭窗口
- Shift+Dlete:永久删除
- Win+D:回到桌面
- Win+E:打开我的电脑
- Win+R:打开运行
- Ctrl+Shift+Esc:打开任务管理器
- Win+Tab:切换应用
- Win+R 输入cmd:打开cmd
二、常用Dos命令
- 盘符切换
- 查看当前目录下所有文件 dir
- 切换目录 cd change directory->cd /d directory
- 返回上一级 cd..
- 清理屏幕 cls(clear screen)
- 退出终端 exit
- 查看版本 java -version
- ping 命令
ping www.baidu.com
- 文件操作
md(创建目录)
rd(移除目录)
cd>(创建文件)
del(删除文件)
三、Markdown语法详解
视频教程
Java学习路线(java黑马学习路线)
一、Java基础(其他参考笔记)
(一)jdk安装与环境配置
jdk安装和配置环境教程视频
(二)IntelliJ IDEA
Ⅰ.开发工具(IntelliJ IDEA)安装
idea破解版安装教程视频
具体步骤
Ⅱ.idea开发java程序步骤
- project(工程)->module(模块)->package(包)->class(类)
- New project/module/package/class
- 编译后的class文件在工程路径下的一个out文件夹里
Ⅲ.idea快捷键
Ⅳ.idea其他操作
视频教程
- @Override(Override注解),它可以指定java编辑器,检查我们方法重写的格式是否正确
- //lombok技术可以实现为类自动添加getter setter方法、无参构造器、toString方法等。
(1)@Data //@Date注解可以自动生成getter setter方法、无参构造器、toString方法等
(2)@NoArgsConstructor //自动生成无参构造器
(3)@AllArgsConstructor //自动生成有参构造器
- @FunctionalInterface //声明函数式接口的注解。标记函数式接口,编译器会检查,如果接口中有多个抽象方法,编译器会报错。
(三)Java基础语法
Ⅰ.注释
- 单行注释://
- 多行注释:/**/
- 文档注释:/** */
Ⅱ.数据类型
- 基本数据类型:4大类8种
- 引用数据类型:String
- 随便写的整数字面量默认是int类型,加上L/l就是long类型的数据了
- 随便写的小数字面量默认是double类型,加上F/f就是float类型的数据了
Ⅲ.标识符
- 标识符就是名字
- 标识符规则:由数字,字母,下划线,美元符等组成,且不能数字开头,不能用关键字,不能用特殊符号(&,%···)
Ⅳ.方法的一些注意事项
- 一个类中,出现多个方法的名称相同,但它们的形参列表是不同的,那么这些方法就称为方法重载。(通过方法名称标记同一功能,通过参数进行差异化。)
- 无返回值的方法中可以直接通过单独的return;立即结束当前方法的执行。
Ⅴ.自动-强制类型转换
- 默认情况下,大范围类型的变量直接赋值给小范围类型的变量会报错
- 可以强行将类型范围大的变量、数据赋值给类型范围小的变量
数据类型 变量=(数据类型)变量、数据
- 大转小可能出些数据丢失
- 小数强制转换成整数是直接截断小数保留整数
Ⅵ.表达式的自动类型提升
- 小范围的类型会自动转换成大范围的类型运算
- 最终类型由表达式中的最高类型决定
- byte short char式直接转换成int类型参与运算的
Ⅶ.输入-输出
- 输入:System.out.println("");
- 输出
(1) 导包(告诉程序去JDK的哪个包中找扫描器技术):import java.util.Scanner;
(2) 得到键盘扫描器对象(东西):Scanner sc=new Scanner(System.in);
(3) 等待接收用户输入数据:String name=sc.next();/int age=sc.nexitInt();
Ⅷ.逻辑运算符
- &:有一个为false、结果是false
- &&:有一个为false、结果是false,但前一个为false,后一个条件就不执行了
- |:有一个为true、结果是true
- ||:有一个为true、结果是true,但前一个为true,后一个条件就不执行了
- ^:相同是false、不同是true
Ⅸ.switch分支-穿透性
点击查看代码- switch(表达式){
- case 值1:
- 执行代码...;
- break;
- case 值2:
- 执行代码...;
- break;
- ...
- case 值n-1:
- 执行代码...;
- braek;
- default:
- 执行代码n;
- }
复制代码
- 表达式类型只能是byte、short、int、char,JDK5开始1支持枚举,JDK7开始支持String、不支持double、float、long。
- case给出的值不允许重复,且只能是字面量,不能是变量。
- 正常使用switch的时候,不要忘记写break,否则会出现穿透现象。
- 存在多个case分支的代码是一样时,可以把代码写到一个case块,其他case块通过穿透性能,穿透到该case块即可,这样可以简化代码。
Ⅹ.三种循环的使用(for、while、do-while)
for循环中,控制循环的变量只在循环中使用。while循环中,控制循环的变量在循环后还可以继续使用。
ⅩⅠ.跳转关键字
- break:跳出并结束当前所在循环的执行。
- 在Java中,带标签的break语句(如break OUT;)用于从多层嵌套的循环或代码块中直接跳出到指定的外层标签位置。
点击查看代码- 标签名:
- for (初始化; 条件; 迭代) {
- // 外层循环
- for (初始化; 条件; 迭代) {
- // 内层循环
- if (某种条件) {
- break 标签名; // 直接跳出到标签指定的循环之后
- }
- }
- }
- // 跳转到这里
复制代码
- continue:用于跳出当前循环的当次执行直接进入循环的下一次执行。
ⅩⅡ.生成随机数
- Math.random()反回[0.0,1.0)的随机数字,Math.random()返回一个double类型的值。
- import java.util.Random;
Random r=new Random();//得到一个随机数对象
int luckNumber=r.nextInt(100)+1;//[0,99]+1=>[1,100]
ⅩⅢ.开平方
Math.sqrt(number)
ⅩⅣ.数组
- 静态初始化数组,定义已经确定了数据
数据类型[] 数组名={元素1,元素2,元素3,…};
如:int[] arr={12,24,36};
- 完整格式
数据类型[] 数组名=new 数据类型[]{元素1,元素2,元素3,…};
如:int[] arr=new int[]{12,24,36};
- "数据类型[] 数组名"也可写成"数据类型 数字名[]"的形式,定义数组的三种方法
1.String[] names={"",""};
2.String names[]={"",""};
3.String[] names=new String[]{"",""};
- names.length: 获取数组的长度(元素个数)
- 动态初始化数组定义数组时先不存入具体的元素,只确定数组存储的数据类型和数组的长度
数据类型[] 数组名=new 数据类型[长度];
int[] arr=new int[3];
- 动态初始化数组元素默认值规则:
(四)面向对象编程
面向对象三大特征:封装、继承、多态。
- 对象
特殊的数据结构,一个实体,有属性和行为。也可以理解为一张表。
- 类(对象类)
特殊的数据结构,有属性和行为。类只在计算机中加载一次。
- 内存分配
java在内存的JVM虚拟机上运行,JVM虚拟机又分为堆内存、栈内存和方法区一同执行程序。
变量存在栈里,变量指向对象,对象存在堆里,对象指向类,类存在方法区,将方法区中的方法调到栈中执行
万物皆对象,一个数据由一个对应的对象处理,我们设计对象时就是在设计类(对象的模板)。
Ⅰ.类的基本语法
- 构造器
(1)构造器(分为无参构造器和有参构造器):类中定义的方法,用来初始化对象,在类中定义的方法,称为方法,在类中定义的变量,称为属性。 名字与类名一致,无返回值,无返回值类型,无访问修饰符。
(2)特点:创建对象时,对象会自动调用构造器,如果没有定义构造器,JVM会自动生成一个无参构造器。
(3)应用场景:创建对象时,调用构造器,立即初始化对象成员变量的值。
(4)注意:类默认有一个无参构造器(没有显示而已),若你自己定义了有参构造器,那么类默认的无参数构造器就没有了,此时如果还想用无参数构造器,就必须自己手写一个无参构造器出来。
- this关键字
(1)this 关键字:是一个变量,可以用在方法中,用来拿到当前对象;哪个对象调用方法,this就指向哪个对象,也就是拿到哪个对象。
(2)应用场景:用来解决对象的成员变量与方法内部变量的名称一样时,导致访问冲突问题的。
点击查看代码- public void print(String name){//this关键字解决变量冲突问题
- System.out.println(name+this.name);//this.name拿到的是对象变量(成员变量)name,而不是局部变量name
- }
复制代码
- 封装
(1)就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去。
(2)封装的设计要求:合理隐藏、合理暴露。
(3)(合理隐藏)使用private(私有、隐藏)关键字进行修饰,防止用户在其他类中随意对本类内的变量修改数据,只允许在本类中直接被访问。
(3)(合理暴露)使用get和set方法,用public(公开)进行修饰,让用户在类外直接调用,修改数据。
- 实体类(JavaBean)
(1)实体类:仅仅只是一个用来保存数据的java类,可以用它创建对象,保存某个事物的数据。
(2)特点:成员变量必须私有,提供get和set方法;必须有无参构造器。
(3)应用场景:实体类的对象只负责数据的封装,不涉及任何业务逻辑。而数据的业务处理交给其他类的对象来完成,以实现数据和业务处理相分离(解耦)。
- static修饰成员变量
(1)static关键字:叫静态,可以修饰成员变量、成员方法。
(2)静态变量(类变量):有static修饰,属于类,在计算机里只有一份,被类的全部对象共享,所有对象都可以访问。
类名.静态变量(推荐)
对象名.静态变量(不推荐)
(3)实例变量(对象的变量):没有static修饰,属于每个对象,每个对象都有自己的变量,对象可以访问。
对象.实例变量
(4)应用场景:如果某一个数据只需要一份,并且希望能够被共享(访问、修改),则该数据被定义成静态变量。 (如用户类,记录了创建了多少个用户对象)
(5)访问自己类中的类变量,可以省略类名不写。
注意:在某个类中访问其他类里的类变量,必须带类名。
- static修饰方法
(1)(有static修饰)静态方法:有static修饰的成员方法,属于类,最好用类名调用,少用对象名调用。
(2)(无static修饰)实例方法:无static修饰的成员方法,属于对象,用对象名调用,不能用类名调用。
规范:如果一个方法只是为了做一个功能且不需要直接访问对象的数据,这个方法直接定义为静态方法。
如果这个方法是关于对象的行为,需要访问对象的数据,这个方法必须定义为实例方法。
(3)比如在main方法中,我们直接调用其他方法,是用类名调用,只不过类名在同一类中可以忽略不写。(main方法是静态方法)
- 工具类与静态方法
(1)工具类:封装了多个静态方法,每个方法用来完成一个功能,给开发人员直接使用。
(2)区别:实例方法需要创建对象来调用,此时对象占用内存,而静态方法不需要,可以减少内存消耗;静态方法可以用类名调用,调用方便,能节省内存。
点击查看代码- public class StaticAbout {//工具类
- //工具类没有创建对象的必要性,建议将工具类的构造器私有化。
- private StaticAbout() {
- }
- public static String getCode(int n) {//静态方法与工具类
- String code = "";
- for (int i = 0; i < n; i++) {
- int type = (int) (Math.random() * 3);//0-9 1-26 2-26
- switch (type) {
- case 0:
- code += (int) (Math.random() * 10);
- break;
- case 1:
- code += (char) (Math.random() * 26 + 'a');//得到小写字母的区间
- break;
- case 2:
- code += (char) (Math.random() * 26 + 'A');
- }
- }
- return code;
- }
- }
复制代码
- 静态方法与实例方法访问注意事项
(1)静态方法中可直接访问静态成员,不可直接访问实例成员。
(2)实例方法中即可直接访问静态成员,也可直接访问实例成员。
(3)实例方法中可以出现this关键字,静态方法中不可出现this关键字。
点击查看代码- public class Attention{
- public static int count=100;//静态变量
- public static void print(){//静态方法
- System.out.println("Hello World!");
- }
- public String name;//实例变量,属于对象
- public void prints(){//实例方法,属于对象
- }
- public static void main(String[] args) {
- }
- //(1)、静态方法中可直接访问静态成员,不可直接访问实例成员。
- public static void printTest1(){
- System.out.println(count);
- print();
- //System.out.println(name);//报错
- //prints();//报错
- //System.out.println(this);//报错,this代表的只能是对象
- System.out.println(Attention.count);
- }
- //(2)、实例方法中即可直接访问静态成员,也可直接访问实例成员。
- public void printTest2(){
- System.out.println(count);
- print();
- System.out.println(name);
- prints();
- System.out.println(this);//实例方法中,this代表的是当前对象
- }
- }
复制代码 Ⅱ.面向对象高级
一)继承
- 继承
(1)继承关键字:extends,可以让一个类与另一个类建立起父子关系
public calss B extends A{}//其中A是父类,B是子类
(2)只能继承父类的非私有成员(成员变量、成员方法)
(3)继承后的创建:子类的对象是由子类、父类共同完成的。
(4)继承的好处:代码重用,减少代码量,提高效率。
- 权限修饰符
用来限制类中的成员(成员变量、成员方法、构造器)能够被访问的范围。
修饰符本类里同一个包中的其他类子孙类(包括不同包的)任意类private√缺省√√protected√√√public√√√√点击查看代码- public class Father {
- private void privateMethod() {//二、2、权限修饰符之私有方法
- System.out.println("private method");
- }
- void defaultMethod() {//二、2、权限修饰符之缺省方法
- System.out.println("default method");
- }
- protected void protectedMethod() {//二、2、权限修饰符之受保护方法
- System.out.println("protected method");
- }
- public void publicMethod() {//二、2、权限修饰符之公共方法
- System.out.println("public method");
- }
- public static void main(String[] args) {//本类中可以调用的所有方法
- Father father = new Father();
- father.privateMethod();
- father.defaultMethod();
- father.protectedMethod();
- father.publicMethod();//所有类都可以调用public方法
- }
- }
- //以下为同一包的子类
- class SonA extends Father {
- public void test() {
- //privateMethod();//子类中不可以访问父类的私有方法
- defaultMethod();//子类中可以访问父类的缺省方法
- protectedMethod();//子类中可以访问父类的受保护方法
- publicMethod();//子类中可以访问父类的公共方法
- }
- }
- //以下为不同包的子类
- class SonC extends Father {
- public void test() {
- //privateMethod();//子类中不可以访问父类的私有方法
- //defaultMethod();//不同包的子类中可以访问父类的缺省方法
- protectedMethod();//不同包的子类中可以访问父类的受保护方法
- publicMethod();//不同包的子类中可以访问父类的公共方法
- }
- }
- //以下为不同包的非子类
- class main {
- public static void main(String[] args) {
- Father father = new Father();
- //father.privateMethod();
- //father.defaultMethod();
- //father.protectedMethod();
- father.publicMethod();//其他包中,只能访问public方法
- }
- }
复制代码 单继承一个类只能继承一个直接父类多层继承不支持多继承,但支持多层继承(多继承的话若两个父类出现相同方法,无法判断调用哪个)祖宗类Java中的所有类都是Object类的子类(一个类要么直接继承Object,要么默认继承Object,要么间接继承)就近原则优先访问自己类中,自己类中的没有才访问父类,父类也没有就报错(访问父类的成员要加super)点击查看代码- public class TestFeature{//测试类
- //二、3、继承的特点
- public static void main(String[] args) {
- zilei zi=new zilei();
- zi.test();
- }
- }
- class fulei{
- String name="FUlei";
- public void run(){
- System.out.println("fuleiRun");
- }
- }
- class zilei extends fulei{
- String name="ZiLei";
- public void run(){
- System.out.println("zileiRun");
- }
- public void test(){
- String name="ZiLeiTEST";
- System.out.println(name);//test的name
- System.out.println(this.name);//zilei的name
- System.out.println(super.name);//fulei的name
- run();//zilei的run优先级更高
- this.run();//zilei的run
- super.run();//fulei的run
- }
- }
复制代码
- 方法重写(声明不变,重新实现)
(1)重写小技巧:使用Override注解(@Override),它可以指定java编辑器,检查我们方法重写的格式是否正确,代码的可读性也会更好。
(2)方法重写:子类写了一个方法名称,形参列表与父类某个方法一样的方法去覆盖父类的该方法。
(3)子类重写父类方法时,访问权限必须大于或等于父类的该方法的权限(public>protected>缺省)
(4)重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
(5)私有方法(不能被继承所以不能被重写)和静态方法(自己调用)不能被重写,否则报错。
点击查看代码- public class TestOverride {
- public static void main(String[] args) {//二、4、方法重写
- animal a=new cat();
- //用父类申明对象,利用多态性和向上转型的概念,以实现更加灵活和可扩展的程序设计,降低代码的耦合性
- a.eat();
- cat b=new cat();
- b.eat();
- }
- }
- class animal{
- public void eat(){System.out.println("animal eat");}
- }
- class cat extends animal{
- @Override//方法重写的校验注解(标志),要求重写的方法与父类方法签名一致,否则编译报错,可读性好
- public void eat(){System.out.println("cat eat!!!");}
- }
复制代码 点击查看代码- public class TestOverride {
- public static void main(String[] args) {
- animal a=new animal();
- System.out.println(a);
- //若没重写toString方法,则返回:com.rasion.extendANDpolymorphism.extend.cat@4e50df2e
- System.out.println(a.toString());
- //我们直接输出对象,会默认调用Object的toString方法,返回对象的地址信息
- //故我们可以重写toString方法,返回我们想要的信息
- }
- }
- class animal{
- private String name;
- @Override
- public String toString() {//重写toString方法,返回我们想要的信息
- return "animal{" +
- "name='" + name + '\'' +
- '}';
- }
- }
复制代码
- 子类构造器
(1)子类构造器,必须先调用父类的构造器,再执行自己的构造器。(可以用super(···)指定调用父类的有参构造器)
(2)默认情况下,子类构造器第一行代码都是super()(写不写都有),他会调用父类的无参构造器,若父类没有无参构造器,则报错。
(3)如果父类没有无参构造器,则我们必须在子类构造器的第一行手写super(···),指定去调用父类的有参数构造器。
(4)应用场景:有一些参数是处在父类中,子类没有,但子类需要用到,这时,子类构造器中,可以先调用父类的有参构造器,为对象中包含父类这部分的成员变量进行赋值,再调用子类的构造器。
- 构造器用this(...)调用兄弟构造器(实现填写默认信息)
(1)一般调用兄弟构造器(在构造器中调用本类的其他构造器),可以实现代码复用。
(2)注意:super(..) this(...)必须写在构造器第一行,并且不能同时出现。(兄弟构造器只需要一个调用父类构造器即可)
点击查看代码- public class User{
- private String name;
- private int age;
- private String school;
- //...此处省略get、set方法toString方法
- public User(String name, int age) {
- this(name, age, "黑马");//调用本类其他构造器,以实现填写默认信息
- }
- public User(String name, int age, String school) {
- this.name = name;
- this.age = age;
- this.school=school;
- }
- }
复制代码 二)多态
- 多态
(1)多态是在继承/实现的情况下的一种现象,表现为:对象多态、行为多态(对象的多样性,行为的多样性,但是没有成员变量的多态性)
(2)多态前提:有继承/实现关系;存在父类引用子类对象;存在方法重写。
(3)注意:多态是对象、行为的多态,java中的属性(成员变量)不谈多态。
点击查看代码- people p1=new student();//对象多态
- p1.run();//行为多态
- people p2=new teacher();//对象多态
- p2.run();//方法:编译看左边,运行看右边
-
- System.out.println(p2.name);//成员变量:编译看左边,运行也看左边
复制代码
- 多态的好处、问题
(1)在多态形式下,右边的对象是解耦合的,更便于扩展和维护。
(2)定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
(3)问题:多态下不能使用子类的独有功能。
点击查看代码- public class TestPolymorphism {
- public static void main(String[] args) {
- people p1=new student();//多态调用不了子类的独有功能
- people p2=new teacher();
- show(p1);
- show(p2);
- System.out.println(p1.name);//成员变量:编译看左边,运行也看左边
- }
- public static void show(people p) {
- //父类类型作为参数,可以接收一切子类变量
- System.out.println("=====+++=====");
- p.run();//调用方法:编译看左边,运行看右边
- }
- }
复制代码
- 多态下的类型转换(instanceof判断)
(1)自动类型转换:父类 变量名=new 子类();例如:People p=new Teacher();
强制类型转换:子类 变量名=(子类) 父类变量;例如:Teacher t=(Teacher)p;
(2)可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题。
(3)存在继承/实现时,就可以进行强制类型转换,编译阶段不会报错。
但在运行时,如果发现对象的真实类型与强制转换后的类型不同,就会报类型异常(ClassCastException)的错误。
(4)在强转前可以用instanceof关键字判断对象的真实类型,再进行强转:对象 instanceof 类型。
点击查看代码- public class TestPolymorphism {
- public static void main(String[] args) {
- people p1=new student();
- people p2=new teacher();
- student s=(student)p1;//强制类型转换
- //teacher t=(teacher)p1;//转换错误,因为p1是student类型
- //编译阶段有类型强转不会报错,运行阶段会报错
- show(p1);
- show(p2);
- }
- public static void show(people p) {
- if(p instanceof teacher) {//判断类型,一般会在方法中写,来判断p是否为teacher类型
- teacher t=(teacher)p;
- ...//调用teacher的独有功能
- }else if(p instanceof student) {
- student s=(student)p;
- ...//调用student的独有功能
- }
- }
- }
复制代码 三)包
- 包就是文件夹,用来管理各种不同功能的java类。
- 包名的书写规则:公司域名反写+包的作用,需要全部英文小写,见名知意。
- 全类名:包名+类名
- 导包
(1)使用同一个包中的类时,不需要导包。
(2)使用java.lang包中的类时,不需要导包。
(3)其他情况都需要导包。
(4)如果同时使用两个包中的同名类,需要用全类名。
四)final(最终的)
- final关键字用来修饰类、方法、变量。
(1)修饰类:代表该类不能被继承,为最终类。(一般是用在工具类中)
(2)修饰方法:代表该方法不能被重写,为最终方法。
(3)修饰变量(局部变量、成员变量(静态、实例)):代表该变量有且仅能被赋值一次。(一般是修饰静态变量)
(4)final修饰基本类型(int,double,boolean,char...)的变量,变量存储的数据不能被改变。
(5)final修饰引用类型(String,Array...)的变量,变量存储的地址不能被改变,但地址所指向的对象的内容是可以被改变的。
2、常量
(1)使用了static final修饰成员变量为常量。
(2)作用:通常使用常量记录系统配置信息;常量都统一到常量包内(Constant),方便修改。
(3)注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。
(4)程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,减少内存消耗,这样可以保证使用常量和直接使用字面量的性能是一样的。
点击查看代码- public class Constant {//常量包
- public static final String NAME = "rasion";
- }
复制代码 五)单例类(设计模式)
- 什么是设计模式:程序中一个问题n种解法中的最优解(设计模式主要学:解决什么问题、怎么写)(设计模式有20多种,对应20多种软件开发中会遇到的问题)
- 单例设计模式
(1)作用:确保某个类只有只能创建一个对象。
(2)把类的构造器私有。(确保单例类对外不能创建太多对象,单例才有可能性)
(3)定义一个类变量存储本类的一个唯一对象。
(4)定义一个类方法,返回这个类的唯一对象。
- 单例应用场景:任务管理器对象、获取运行时对象(有且仅需要一个对象)
- 饿汉式单例类:在获取类的对象时,对象已经创建好了。
点击查看代码- public class A {//饿汉式单例类:拿对象的时候对象早已生成,无论是用不用,都会创建。
- private A(){}//1、私有化构造器
- private static A a=new A();//2、实例化私有静态变量
- //当类被加载时,静态变量a会被初始化,此时类的私有构造函数会被调用。这时候,单例类的唯一实例就被创建出来了。
- public static A getObject(){
- return a;
- }//3、定义一个类方法返回对象
- }
复制代码
- 懒汉式单例类:用对象时,才开始创建对象(延迟加载对象)。
(1)把类的构造器私有。
(3)定义一个静态(类)变量用于存储对象。
(4)提供一个静态(类)方法,保证返回的是同一个对象。
点击查看代码- public class B {//懒汉式单例类:拿对象的时候才创建,真正需要对象时才开始创建。
- private B(){}//1、私有化构造器
- private static B b;//2、定义一个类变量用于存储对象
- public static B getInstance(){//提供一个类方法返回类的唯一对象
- if(b==null){
- //第一次拿对象时,会创建对象,给静态变量b记住。
- b=new B();
- }
- return b;
- }
- }
复制代码 六)枚举类(一种特殊类)
- 枚举类的写法:
修饰符 enum 枚举类名{
名称1,名称2,名称3;
其他成员...
}
- 特点:
(1)枚举类中的第一行,只能写枚举类的对象名称,且要用逗号隔开。
(2)这些名称,本质是常量,每个常量都记住了枚举类的一个对象。
(3)枚举都是最终类,不可以被继承,枚举类都是继承java.lang.Enum类的。
点击查看代码- public enum A {//枚举类
- X,Y,Z;//枚举类第一行只能罗列一些名称,这些名称都为常量,并且每个常量会记住枚举类的一个对象
- }
- Compiled from "A.java"//对A.java的反编译
- public final class A extends java.lang.Enum{//枚举类继承了Enum
- public static final A X=new A();//枚举类第一行只能罗列一些名称,这些名称都为常量,并且每个常量会记住枚举类的一个对象
- public static final A Y=new A();//如果只有一个Y的话,可以被视为单例类。
- public static final A Z=new A();
- //枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- public static A[] values();//返回枚举类的所有实例
- public static A valueOf(java.lang.String var0);//返回指定名称的枚举实例
- }
复制代码
- 枚举类的常用应用场景:适合做信息分类和标志
(1)枚举类常用于定义常量,枚举类中的常量只能是枚举类的实例,不能被修改。
(2)虽说用也可以用常量类做信息分类和标志,但是参数值不受约束(就是传入的参数不是限定内的那四个都能行的通,写别的不报错),但是枚举类的话写限定外的就会报错。
七)抽象类
- 在java中有一个关键字叫:abstract(抽象),可以用它修饰类、成员方法。
- abstract修饰类,这个类就是抽象类。
- abstract修饰方法,这个方法就是抽象方法。
修饰符 abstract class 类名{
修饰符 abstract 返回值类型 方法名称(形参列表);
}
抽象方法只有方法签名,不能写方法体。
- 抽象类的注意事项、特点
(1)抽象类不一定要有抽象方法,有抽象方法的类必须是抽象类。
(2)类有的成员:成员变量、方法、构造器,抽象类都可以有。
(3)抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
(4)一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类。
点击查看代码- public abstract class A {//抽象的本质是不能有对象,抽象类的基本作用就是被继承
- private String name;//抽象类有成员变量
- public A(){System.out.println("抽象类A的构造方法");}//抽象类有构造方法
- public void show(){System.out.println("抽象类A的show方法");}//抽象类的方法可以有方法体
- //抽象方法,抽象类中可以有没有抽象方法,抽象方法没有方法体,只有方法声明,子类必须重写抽象方法
- public abstract void show();//抽象类的抽象方法不能写方法体
- }
复制代码
- 抽象类的应用场景和好处:父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态。(抽象类简化了需要重写的父类方法的代码,更加便于调用子类时多态的实现,更具解耦性。)
- 模板方法设计模式:
(1)提供了方法作为完成某类操作的模板,模板方法封装了每个实现步骤,允许子类实现特定步骤的实现。
(2)解决方法中存在重复代码的问题。
(3)定义一个抽象类,在里面定义2个方法,一个是模板方法:放相同的代码,一个是抽象方法:具体实现交给子类完成。
(4)建议使用final关键字修饰模板方法。(模板方法不能被子类重写,一旦子类重写了模板方法,模板方法就失效了)
点击查看代码- public abstract class fu {//父类抽象类
- public final void show(){//模板方法不能被重写
- System.out.println("模板方法");//子类共同的部分
- show1();//子类不同的部分
- }
- public abstract void show1();//抽象方法,子类一定要重写,不然就报错,这样做是最佳实现
- }
- public class A extends fu {//子类
- @Override
- public void show1(){System.out.println("A show1方法");}
- }
- public class B extends fu {//子类
- @Override
- public void show1(){System.out.println("B show1方法");}
- }
复制代码 八)接口(相当于干爹)
- Java提供了一个关键字interface定义出接口。
public interface 接口名{
//成员变量(常量)
//成员方法(抽象方法)
}
(1)传统接口:内部只能写常量和抽象方法(jdk8以前)。
(2)常量:接口中的常量默认是public static final的,所以可以省略。
(3)抽象方法:接口中的抽象方法默认是public abstract的,所以可以省略。
(4)没有构造方法。
- 注意:接口不能创建对象。
- 接口是用来被类实现(implements)的,实现接口的类称为实现类,一个类可以同时实现多个接口。
修饰符 class 实现类类名 implements 接口1,接口2,接口3,···{
//实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
}
点击查看代码- public interface A {//接口不能创建对象,只能被实现
- //JDK-8之前,接口只能定义常量和抽象方法,不能定义具体方法。
- //1、常量:接口中的常量默认是public static final的,所以可以省略。
- String NAME="rasion";
- //2、抽象方法:接口中的抽象方法默认是public abstract的,所以可以省略。
- // public abstract void show();
- void show();
- }
- public class C implements A,B {//实现接口的类,可以实现多个接口
- @Override
- public void show() {
- System.out.println("C实现A\B接口的show方法");
- }
- }
复制代码
- 接口的好处:
(1)弥补了类单继承的不足,可以实现多接口,使类的角色更多,功能更加强大(接口可以是一种属性)。
(2)让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)。
点击查看代码- public class test {
- public static void main(){
- // Driver d=new Teacher();//做接口解耦合,可以不改变自己本来的代码
- Driver d=new Student();
- Cook c=new Student();
- }
- }
- public interface Driver {}
- public interface Cook {}
- class people{}//抽象类
- class Teacher extends people implements Driver,Cook{}//实现多个接口,用逗号隔开
- class Student extends people implements Driver,Cook{}
复制代码
- JDK8开始,接口新增了三种形式的方法:
(1)默认方法:使用default修饰,使用实现类的对象调用。
(2)静态方法:static修饰,必须当前接口名来调用。
(3)私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。
(4)他们都会默认被public修饰。
(5)新增的方法增强接口能力,更便于项目扩展与维护(若新增方法,可以直接写在接口中,不用修改实现类,更方便扩展)
点击查看代码- //jdk-8之后的三种方法
- //a、默认方法,一定要加default修饰符,默认会用public修饰,用接口的实现类对象调用
- default void defaultMethod(){
- System.out.println("defaultMethod");
- privateMethod();
- }
- //b、静态方法,一定要加static修饰符,默认会用public修饰,只能用当前接口名来调用
- static void staticMethod(){//静态方法
- System.out.println("staticMethod");
- }
- //c、私有方法,一定要加private修饰符,默认会用private修饰,用接口中的其他实例方法调用
- private void privateMethod(){//私有方法
- System.out.println("privateMethod");
- }
复制代码
- 注意事项:
(1)接口与接口可以多继承,一个接口可以同时继承多个接口,但接口不能继承类。
类与类:单继承,一个类只能继承一个直接父类。
类与接口:多实现,一个类可以同时实现多个接口
(2)一个接口继承多个接口,若多个接口中出现方法签名冲突,此时不支持多继承,也不支持多实现(即两个接口都有同一个方法名,但是方法签名不同,即方法类型不同,则报错)。
(3)一个类继承了父类,同时又实现接口,若父类与接口中有同名的方法,则会优先实现父类的方法。(若想调用接口的方法只能新建中专方法,接口名.super.方法名)
(4)一个类实现多个接口,如果多个接口中存在同名的默认方法,要想不冲突,这个类重写该方法即可。
- 抽象类与接口区别:
相同点:
(1)都是抽象形式,都可以有抽象方法,都不能创建对。
(2)都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现。
(3)一个类继承抽象类,或者实现接口,都必须重写他们的抽象方法,否则自己要成为抽象类或者报错!
(4)都能支持多态,都能实现解耦合。
不同点:
(1)抽象类中可以定义类的全部普通成员,接口只能定义常量、抽象方法,(JDK8新增的三种方式)。
(2)抽象类只能被类单继承,但是接口可以被类多实现。
(3)一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)。
(4)抽象类体现模板思想,更利于做父类的,实现代码的复用性;接口更适合做功能的解耦合,解耦合更加灵活。(最佳实现)
九)代码块
- 类的五大成分:成员变量、构造器、方法、代码块、内部类。
- 静态代码块:
(1)格式:static{ }
(2)特点:类加载时自动执行,由于类只会加载一次,所以静态代码块只执行一次,优先考虑于构造器执行。
(3)作用:完成类的初始化(如:对静态变量的初始化赋值)。
(4)import java.util.Arrays:
System.out.println(Arrays.toString(cards));//返回数组的内容观察
- 实例代码块
(1)格式:{ }
(2)特点:每次创建对象时,执行实例代码块,并在构造器前执行。
(2)作用:和构造器一样,都是用来完成对象的初始化的(如:对实例变量进行初始化赋值)。
点击查看代码- public class codeBlock {
- public static String NAME;
- public static String[] CARD=new String[54];//初始化数组
- static {//静态代码块,有static修饰,属于类,与类一起优先加载,自动执行一次
- System.out.println("static block");
- NAME="rasion";
- CARD[0]="A";//静态数组只需要初始化一次,就可以在静态代码块中初始化
- CARD[1]="2";
- CARD[2]="3";
- }
- {//实例代码块,没有static修饰,属于对象,与对象一起加载,对象加载几次,就会执行几次
- System.out.println("non-static block");
- }
- public static void main(String[] args) {
- System.out.println("hello main");
- System.out.println(NAME);
- System.out.println(Arrays.toString(CARD));//打印数组
- codeBlock cb=new codeBlock();//创建对象时,会执行实例代码块
- new codeBlock();
- new codeBlock();
- System.out.println(cb);
- }
- }
复制代码 十)内部类
- 当一个类被定义在另一个类内部,则该类称为内部类。
- 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
- 成员内部类:
(1)就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法。
(2)创建成员内部类对象格式:
外部类名.内部类名 对象名= new 外部类名().new 内部类名();
Outer.Inter in=new Outer().new Inter();
(3)成员内部类属于外部类对象持有。
(4)成员内部类可以直接访问外部类的静态成员、实例成员。
(5)成员内部类的实例方法中,可以直接拿到当前寄生的外部类对象,格式是:外部类.this.成员名。
点击查看代码- public class main {
- public static void main(String[] args) {
- // 创建成员内部类对象格式:外部类名.内部类名 对象名= new 外部类名().new 内部类名();
- OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
- innerClass.print();//内部类对象调用内部类方法
- }
- }
- public class OuterClass {
- //成员内部类:无static修饰,属于外部类的对象持有的
- public class InnerClass{//类有的属性,方法内部类都能有
- private String num="InnerThis";
- public void print(){
- System.out.println("===innerMethod===");
- outerPrint();
- String num="-innerPrint-";
- System.out.println(num);
- System.out.println(this.num);//内部类对象
- System.out.println(OuterClass.this.num);//外部类对象
- OuterClass oc=new OuterClass();//创建外部类对象
- System.out.println(oc.num);
- run();
- }
- }
- //内部类可以访问外部类的静态成员
- public static void outerPrint(){//外部类静态方法
- System.out.println("OuterClass static print");
- }//静态内部类,属于外部类,外部类可以访问
- private String num="OuterThis";//外部类成员变量
- public void run(){}
- }
复制代码
- 静态内部类:
(1)有static修饰的内部类,属于外部类自己持有。
(2)创建静态内部类对象格式:
外部类名.内部类名 对象名= new 外部类名.内部类名();
Outer.Inner in=new Outer.Inner();
(3)静态内部类可以直接访问外部类的静态成员;静态内部类不可以直接访问外部类的实例成员。
点击查看代码- public class main {
- public static void main(String[] args) {
- StaticInnerClass.InnerClass innerClass=new StaticInnerClass.InnerClass();//静态内部类对象
- innerClass.print();
- }
- }
- public class StaticInnerClass {
- public static class InnerClass{
- private String NAME="inner rasion";
- public void print() {
- System.out.println("StaticInnerClass print");
- //静态内部类可以直接访问外部类的静态成员
- System.out.println("StaticInnerClass NAME:"+StaticInnerClass.NAME);
- //静态内部类不可以直接访问外部类的实例成员
- // System.out.println("StaticInnerClass age:"+age);
- //静态内部类可以间接访问外部类的局部变量
- StaticInnerClass staticInnerClass=new StaticInnerClass();
- System.out.println("StaticInnerClass age:"+staticInnerClass.age);
- }
- }
- public static String NAME="outer rasion";//外部类的静态成员
- public int age=18;//外部类的实例成员,属于外部类对象的
- }
复制代码
- 局部内部类:(了解)
局部内部类:定义在方法中、代码块中、构造器等执行体中(无具体意义,用来引出匿名内部类)。
- 匿名内部类:
(1)一种特殊的局部内部类。
(2)所谓匿名:指的是程序员不需要为这个类声明名字,默认有一个隐藏的名字。
new 类名或接口(参数值...){
类体(一般是方法重写);
};
new Animal(){
@Override
public void cry(){}
};
(3)特点:匿名内部类本质是个子类,并且会立即创建出一个子类对象。
(4)作用:更方便的创建一个子类对象。
(5)匿名内部类在开发中的常见形式:通常作为一个对象参数传输给方法。
(6)匿名内部类在开发中的真实使用场景示例
调用别人提供的方法实现需求时,这个方法正好可以让我们传输一个匿名内部类对象给其使用。(开发中不是主动写匿名内部类,而是调用别人的功能时,需要我们写一个匿名内部类)
点击查看代码- public class AnonymityInnerClass {
- public static void main(String[] args) {
- //匿名内部类有名字:外部类名$编号.class
- //匿名内部类本质是一个子类,同时立即创建一个子类对象
- Animal cat=new Animal(){
- @Override
- public void run() {System.out.println("cat run");}
- };//匿名内部类,同cat类,即是一个子类又是一个子类对象
- // Animal cat=() -> System.out.println("cat run");//Lambda简化
- cat.run();
- print(cat);
-
- print(new Animal() {
- @Override
- public void run() {System.out.println("inner cat run");}
- });//同上print(cat);一样功能
- }
- public static void print(Animal animal){
- System.out.println("start==");
- animal.run();//匿名类对象回调,由于匿名类相当于子类,所以可以调用子类的方法
- }
- }
- interface Animal{
- public abstract void run();
- }
- //class cat extends Animal{
- // @Override
- // public void run() {
- // System.out.println("cat run");
- // }
- //}
复制代码 十一)函数式编程
- 此“函数”类似于数学中的函数(强调做什么),只要输入的数据一致返回的结果也是一致的
数学中的函数示例:2x+1
Java中的函数(Lambda表达式):(x->2x+1)
- 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。
- Lambda表达式
(1)JDK8新增的一种语法,代表函数。
(2)可以用于替代并简化函数式接口的匿名内部类,从而让程序更简洁,可读性更好。
Lambda表达式的格式:(被重写方法的形式参数列表)->{匿名内部类被重写的方法体代码}
(3)注意:Lambda表达式只能替代函数式接口的匿名内部类!!!
(4)函数式接口:有且仅有一个抽象方法的接口。
(5)注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,该注解用于约束当前接口必须是函数式接口。
(6)Lambda表达式的省略规则(用于进一步简化Lambda表达式的写法):
a、参数类型可以省略不写。
b、如果只有一个参数,参数类型省略的同时“( )”可以省略,但多个参数不能省略“( )”
c、如果Lambda只有一行代码,大括号可以省略,同时必须省略分号“;”,如果这行代码是return语句,也必须去掉return。
点击查看代码- public class main {
- public static void main(String[] args) {
- //函数式接口:
- MyInterface myInterface1 = () -> {
- System.out.println("lambda表达式简化匿名内部类");
- };
- myInterface1.print();
-
- //public static void sort(T[] a, Comparator<T> c)——————作用:数组按照某个值重排序
- //参数一:需要排序的数组 参数二:需要给sort声明一个Comparator比较器对象(指定排序的规则)
- Arrays.sort(students,new Comparator<Student>() {//Comparator为由官方定义的函数式接口
- @Override
- public int compare(Student o1, Student o2) {
- //如果左边对象大于右边对象,返回正整数,否则返回负整数,等于时为0
- return o1.getAge()-o2.getAge();//或写成这样,按照年龄升序
- }
- });
- Arrays.sort(students, (o1, o2)-> o1.getAge()-o2.getAge());//以上部分简化后的代码
- }
- }
- //函数式接口:只有一个抽象方法的接口
- @FunctionalInterface//标记函数式接口,编译器会检查,如果接口中有多个抽象方法,编译器会报错
- interface MyInterface{
- //抽象方法
- public abstract void print();
- }
复制代码
- 静态方法引用
(1)格式:类名::静态方法名
(2)使用场景:如果某个Lambda表达式里仅调用了一个静态方法,并且"->"前后的参数形式一致,则可以使用静态方法引用。
点击查看代码- // Arrays.sort(students, (o1, o2)-> o1.getAge()-o2.getAge());//Student没有加compareByAge方法时
- Arrays.sort(students,(o1, o2)->Student.compareByAge(o1,o2) );//Student加compareByAge方法时可化简,Lambda表达式实现
-
- Arrays.sort(students, Student::compareAge);//静态方法引用简化后的代码
- public class Student{
- ...(详见Student类)
- public static int compareByAge(Student o1, Student o2){
- return o1.getAge()-o2.getAge();
- }
- }
复制代码
- 实例方法引用
(1)格式:对象名::实例方法名
(2)使用场景:如果某个Lambda表达式里只通过对象名称调用一个实例方法,并且"->"前后的参数形式一致,则可以使用实例方法引用。
点击查看代码- Student t=new Student();//创建一个实例对象
- Arrays.sort(students, (s1,s2) -> t.compareByHeight(s1,s2));//Lambda使用方式
-
- Arrays.sort(students, t::compareByHeight);//实例方法引用
-
- public class Student{
- ...(详见Student类)
- public int compareByHeight(Student o1, Student o2){
- //按身高升序排序
- return Double.compare(o1.getHeight(),o2.getHeight());
- }
- }
复制代码
- 特定类的方法引用
(1)格式:特定类型名称(如:String)::方法名
(2)使用场景:如果某个Lambda表达式里只调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为实例方法的入参的,则此时就可以使用特定类型的方法引用。
点击查看代码- Arrays.sort(names, new Comparator<String>() {
- @Override
- public int compare(String o1, String o2) {
- return o1.compareToIgnoreCase(o2);//字符串按照首字母忽略大小写比较的方法
- }
- });//匿名内部类的代码
- Arrays.sort(names,(o1, o2)-> o1.compareToIgnoreCase(o2));//Lambda简化后的代码
-
- Arrays.sort(names,String::compareToIgnoreCase);//特定类的方法引用
复制代码
- 构造器引用
(1)格式:类名::new
(2)使用场景:如果某个Lambda表达式里只是创建对象,并且"->"前后的参数形式一致,则可以使用构造器引用。
点击查看代码- package com.itheima.method1reference;
- import jdk.jfr.DataAmount;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- public class Demo4 {
- public static void main(String[] args) {
- // CarFactory cf = new CarFactory() {
- // @Override
- // public Car getCar(String name) {
- // return new Car(name);
- // }
- // };//匿名内部类
- // CarFactory cf= name -> new Car(name);//Lambda代码
- //以上两种代码简化后的代码:
- CarFactory cf= Car::new;//构造器引用
- Car c1 = cf.getCar("奔驰");
- System.out.println(c1);
- }
- }
- @FunctionalInterface
- interface CarFactory{
- Car getCar(String name);
- }
- @Data//封装数据
- @AllArgsConstructor//有参构造器
- @NoArgsConstructor
- class Car{
- private String name;
- }
复制代码 十二)常用API(应用程序编程接口)
简单理解:API就是别人写好的东西,我们不需要自己编写,直接使用即可。
Java API:指的就是JDK中提供的各种功能的Java类。
- String(代表字符串,它的对象可以封装字符串数据,并提供了很多方法完成对字符串的处理)
- String创建字符串对象的方式
(1)方式一(推荐):直接“”就可以创建字符串对象,封装字符串数据(java程序中的所有字符串文字(例如”abc“)都为此
String name="小黑";
String schoolName="黑马程序员";
(2)方式二:调用String类的构造器初始化字符串对象。
(3)只要以”...“方式创建字符串对象,会存储到字符串常量池中,且相同字符串只会储存一份。
(4)通过 new 方式创建字符串对象,每new一次,都会产生一个新的对象放在堆内存中。
(5)字符串对象的内容比较,千万不要用,默认比较地址,字符串对象的内容一样时地址不一定一样。
点击查看代码- //方式一(推荐):直接“”就可以创建字符串对象,封装字符串数据
- String s1="hello,黑马";//快速创建字符串
- System.out.println(s1);//输出hello,黑马而不是地址
- //方式二:通过构造器初始化对象。
- String s2=new String();//不推荐
- System.out.println(s2);//”“空字符串
- String s3=new String("hello,黑马");//不推荐
- char[] chs={'h','e','l','l',',','黑','马'};
- String s4=new String(chars);//把字符数组转换成字符串
- byte[] bytes={97,98,99,65,66,67};
- String s5=new String(bytes);
- System.out.println(s5)
- String t1="abc";
- String t2="abc";
- System.out.println(t1=t2);//字符串在常量池且只有一份,故为true
- String t3=new String("abc");
- String t4=new String("abc");
- System.out.println(s3==s4);//new出字符串对象,故为false
复制代码 构造器说明public String()创建一个空白字符串对象,不含任何内容public String(String original)根据传入的字符串内容,来创建字符串对象public String(char[] chars)根据字符数组的内容,来创建字符串对象public String(byte[] bytes)根据字节数组的内容,来创建字符串对象方法名说明public int length()获取字符串长度返回(字符个数)public char charAt(int index)获取某个索引位置处的字符返回public char[ ] toCharArray()讲当前字符串转换成字符数组返回public boolean equals(Object anObject)判断当前字符串与另一个字符串的内容是否一样,一样返回truepublic boolean equalsIgnoreCase(String anotherString)判断当前字符串与另一个字符串的内容是否一样(忽略大小写)public String substring(int beginIndex,int endIndex)根据开始和结束索引进行截取,得到新的字符串(包前不包后)public String substring(int beginIndex)从传入的索引处截取,截取到末尾,得到新的字符串返回public String replace(CharSequence target,CharSequence replacement)使用新值,讲字符串中的旧值替换,得到新的字符串public boolean containt(CharSequence s)判断字符串中是否包含了某个字符串public boolean startsWith(String prefix)判断字符串是否以某个字符串内容为开头,是则返回truepublic String[ ] split(String regex)把字符串按照某个字符串内容分割,返回字符串数组回来
- ArrayList
(1)集合是一种容器,用来装数据的,类似数组,但是容量大小可变,功能丰富,开发中用的更多。
(2)ArrayList是集合中最常用的一种,ArrayList是泛型类,可以约束存储的数据类型。
ArrayList list=new ArrayList();
(3)创建ArrayList对象,代表一个集合容器(调用无参构造器public ArrayList()初始化对象):ArrayList list=new ArrayList();
(4)创建ArrayList对象时,如果没有用泛型,则调用get方法时返回Object类型的数据。
(4)调用ArrayList提供的方法,对容器中的数据进行增删改查操作。
(5)遍历集合:for(int i=0;iError/ (Excetion-->RuntimeException/其他异常)
(1)Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出问题,sun公司会把这些异常封装成Error对象抛出(Error是给sun公司自己用的,不是给程序员用的,因此我们开发人员不用管他),如:内存溢出、栈溢出等。
(2)Exception:异常,它代表的才是程序运行过程中出现的问题,程序员通常会用Exception以及它的孩子来封装程序出现的问题。(又分为运行时异常和编译时异常)
-- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现异常(如:数组索引越界异常)。
-- 编译时异常:编译阶段就会出现错误提醒。(如:日期解析异常、语法错误、类型转换错误等)
- 异常的基本处理
(1)抛出异常(throws):在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。
(2)捕获异常(try...cath):直接捕获程序出现的异常。
- private static void createWindow() {//以下为创建窗口和一个按钮的代码
- JFrame frame = new JFrame("登录窗口");//创建窗口
- JPanel panel = new JPanel();//创建面板
- frame.add(panel);//将面板添加到窗口中
- frame.setSize(300, 200);//设置窗口大小
- frame.setLocationRelativeTo(null);//设置窗口居中
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口默认操作:关闭窗口,推出程序
- JButton button=new JButton("登录");//创建按钮
- //button.setBounds(100,100,80,30);//设置按钮位置和宽高
- panel.add(button);//添加按钮到面板,使按钮能够自适应窗口大小
- frame.setVisible(true);//显示窗口
- }
复制代码- JFrame frame = new JFrame("FlowLayout布局管理器");
- frame.setSize(400, 300);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setLayout(new FlowLayout());//设置窗口的布局管理器对象
- frame.add(new JButton("按钮1"));
- frame.add(new JButton("按钮2"));
- frame.setVisible(true);
复制代码 点击查看代码- JFrame frame = new JFrame("BorderLayout布局管理器");
- frame.setSize(400, 300);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setLayout(new BorderLayout());//设置窗口的布局管理器对象
- frame.add(new JButton("按钮1"), BorderLayout.NORTH);
- frame.add(new JButton("按钮2"), BorderLayout.SOUTH);
- frame.add(new JButton("按钮3"), BorderLayout.CENTER);
- frame.add(new JButton("按钮4"), BorderLayout.EAST);
- frame.add(new JButton("按钮5"), BorderLayout.WEST);
- frame.setVisible(true);
复制代码 Ⅱ.异常作用
- 用来定位程序bug关键信息
- 可以作为方法内的一种特殊的返回值,以便通知上层调用者,方法的执行出现问题,用来查找bug。
点击查看代码- JFrame frame = new JFrame("GridLayout布局管理器");
- frame.setSize(400, 300);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setLayout(new GridLayout(2, 3));//设置窗口的布局管理器对象
- for (int i = 0; i < 6; i++) {
- frame.add(new JButton("按钮" + i));
- }
- frame.setVisible(true);
复制代码 Ⅲ.自定义异常
- Java无法为全部的问题都提供异常类来代表,企业内部某种问题想通过异常管理,以便用异常来管理问题,需要自定义异常类。
- 自定义编译异常:
(1)定义一个异常类继承Exception类。
(2)并重写构造器。
(3)通过throw new 异常类(xxx) 创建异常对象并抛出。
特点:编译阶段就报错,提醒比较激进。
- 自定义运行时异常:
(1)定义一个异常类继承RuntimeException类。
(2)并重写构造器。
(3)通过throw new 异常类(xxx) 创建异常对象并抛出。
特点:编译阶段不报错,运行时才可能出现!提醒不属于激进型。
- 如果想要表达强烈的提醒(他人易犯的错误),就要用编译时异常(少用),若然程序员自己能避免(别人不易犯错),就使用运行时异常(多用)。
点击查看代码- JFrame frame = new JFrame("BoxLayout布局管理器");
- frame.setSize(400, 300);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));//垂直排列
- panel.add(new JButton("按钮1"));
- panel.add(Box.createVerticalStrut(10));//垂直间距
- panel.add(new JButton("按钮2"));
- panel.add(Box.createVerticalStrut(10));
- panel.add(new JButton("按钮3"));
- frame.add(panel);
- frame.setVisible(true);
复制代码 Ⅳ.异常处理方案
- 底层异常层层上抛,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提醒。
- 最外层获取异常后,尝试重新修复。
点击查看代码- JFrame jf=new JFrame("登录窗口");
- JPanel panel=new JPanel();//创建一个面板
- jf.add(panel);//将面板添加到窗口中
- jf.setSize(400,300);//设置窗口大小
- jf.setLocationRelativeTo(null);//设置窗口居中
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的默认操作:关闭窗口退出程序
- JButton jb=new JButton("登录");//创建一个按钮
- panel.add(jb);//将按钮添加到面板中
- //给按钮绑定点击事件监听对象。
- jb.addActionListener(new ActionListener(){
- @Override
- public void actionPerformed(ActionEvent e){
- //一旦你点击jb按钮,底层触发这个方法执行
- //e 是事件对象,封装了事件相关信息
- JOptionPane.showMessageDialog(jf,"有人点击了登录");
- }
- });
- jf.setVisible(true);//显示窗口
复制代码 (二)泛型
Ⅰ.认识泛型
- 定义类、方法、接口时,同时声明了一个或多个类型变量(如:< E >)称为泛型类、泛型接口、泛型方法,它们统称为泛型。
- JFrame jf=new JFrame("登录窗口");
- JPanel panel=new JPanel();//创建一个面板
- jf.add(panel);//将面板添加到窗口中
- jf.setSize(400,300);//设置窗口大小
- jf.setLocationRelativeTo(null);//设置窗口居中
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的默认操作:关闭窗口退出程序
- JButton jb=new JButton("登录");//创建一个按钮
- panel.add(jb);//将按钮添加到面板中
- //需求:监听用户键盘上下左右四个按键的事件。
- //给jf窗口整体绑定按键事件。
- jf.addKeyListener(new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e){
- System.out.println("========AAAAAAA========");
- //获取键盘按键的编码
- int keyCode=e.getKeyCode();//拿事件源头的键帽编号
- //判断按键编码是否是上、下、左、右
- if(keyCode==KeyEvent.VK_UP){
- System.out.println("用户点击了上");
- }else if(keyCode== KeyEvent.VK_DOWN){
- System.out.println("用户点击了下");
- }else if(keyCode== KeyEvent.VK_LEFT) {
- System.out.println("用户点击了左");
- }else if(keyCode== KeyEvent.VK_RIGHT) {
- System.out.println("用户点击了右");
- }
- }
- });
- jf.setVisible(true);//显示窗口
- //让窗口成为焦点
- jf.requestFocus();
复制代码
- 作用:提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力,可以避免强制类型转换,及其有可能出现的异常。
- 泛型本质:把具体的数据类型作为参数传给类型变量。
Ⅱ.泛型类
- 基本语法:修饰符 class 类名{ }
- 注意:类型变量用大写字母,如:T、E、K、V等。
- 可以控制类接收的类型变量,由于支持多个类型变量,故需注意类型变量的顺序,如:、之类的。
- 应用场景:在工具类中,经常会有一些方法需要处理不同类型的对象,如集合操作、数据转换等,这时可以使用泛型方法来增强工具类的通用性。
Ⅲ.泛型接口
- 基本语法:修饰符 interface 接口名{ }
- 注意:类型变量用大写字母,如:T、E、K、V等。
点击查看代码- package com.itheima.gui;
- import javax.swing.*;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- public class Test2 {
- public static void main(String[] args) {
- JFrame jf = new JFrame("登录窗口");
- JPanel panel = new JPanel();//创建一个面板
- jf.add(panel);//将面板添加到窗口中
- jf.setSize(400, 300);//设置窗口大小
- jf.setLocationRelativeTo(null);//设置窗口居中
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的默认操作:关闭窗口退出程序
- JButton jb = new JButton("登录");//创建一个按钮
- panel.add(jb);//将按钮添加到面板中
- jb.addActionListener(new MyActionListener(jf));
- jf.setVisible(true);
- }
- }
- //实现类
- class MyActionListener implements ActionListener{
- private JFrame jf;
- public MyActionListener(JFrame jf){
- this.jf=jf;
- }
- @Override
- public void actionPerformed(ActionEvent e){
- JOptionPane.showMessageDialog(jf,"有人点击了登录!");
- }
- }
复制代码 Ⅳ.泛型方法、通配符、上下限
- 泛型方法
修饰符 返回值类型 方法名(形参列表){}
public static void test(T t){}
- 泛型方法作用:泛型方法可以避免强制类型转换,在编译时就能够报错,同时能够确保方法接收参数的多样性,提升方法的复用性。
点击查看代码- JFrame jf=new JFrame("登录窗口");
- JPanel panel=new JPanel();//创建一个面板
- jf.add(panel);//将面板添加到窗口中
- jf.setSize(400,300);//设置窗口大小
- jf.setLocationRelativeTo(null);//设置窗口居中
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的默认操作:关闭窗口退出程序
- JButton jb=new JButton("登录");//创建一个按钮
- panel.add(jb);//将按钮添加到面板中
- //给按钮绑定点击事件监听对象。
- jb.addActionListener(new ActionListener(){
- @Override
- public void actionPerformed(ActionEvent e){
- //一旦你点击jb按钮,底层触发这个方法执行
- //e 是事件对象,封装了事件相关信息
- JOptionPane.showMessageDialog(jf,"有人点击了登录");
- }
- });
- jf.setVisible(true);//显示窗口
复制代码
- 通配符(wildcard):
就是“?”,可以在“使用泛型”的时候代表一切类型;ETKV是在定义泛型的时候使用。(通配符是泛型类型的占位符)
- 泛型的上下限:
(1)泛型上限:? extends Car表示只能接受Car或者其子类。
(2)泛型下限:? super Car表示只能接受Car或者其父类。
点击查看代码[code]public class WildcardGeneric { public static void main(String[] args) { ArrayList cars = new ArrayList(); cars.add(new Car()); cars.add(new Bmw()); cars.add(new BYD()); run(cars);//输出:汽车在跑\n宝马在跑\n比亚迪在跑 ArrayList bmws = new ArrayList();// run(bmws);//报错,因为集合里面只能是Car类 bmws.add(new Bmw()); SystemOut(bmws);//输出:BMW } public static void run(ArrayList cars){ //这里是虽然是父类,但是只能够访问Car类,不能访问子类,不像多态 for (Car car : cars) { car.run(); } } public static void SystemOut(ArrayList |