目录
一、类和对象
1.类和对象
1.1.对象
什么是对象?一切可以被描述的事物(实体)。
对象的特征是什么?任何对象都具有属性和方法。
什么是属性?对象的特征、状态。
什么是方法?对象的行为、动作和操作。
1.2.类
是相似对象的集合,是实体对象的抽象描述,是创建对象的模板,是一种引用数据类型。
1.3.类和对象的关系
类是抽象的,对象是具体的,类是对象的抽象;
类是一个模板,在类中定义了对象共同的特征和行为,通过此模板创建的对象都有共同的特征和行为;
类是一种引用数据类型,对象是堆中的一个实体。
1.4.Java类的语法
访问修饰符 class 类名{
成员:成员变量、静态变量、成员方法、静态方法、构造器、构造块、静态代码块、内部类
}
说明:
访问修饰符:public,默认
2.属性:在类中定义的非静态变量,也被称为成员变量
2.1.属性声明
格式:访问修饰符 数据类型 变量名 = 变量值;
- 访问修饰符:public,protected,默认,private
- 返回值类型:基本型和引用类型
- 变量名:首字母小写,遵循驼峰法则
- 变量值:可选的
2.2.初始化初始化
在new创建对象的时候被初始化。属于系统自动初始化。且使用各数据类型的默认值。初始化顺序:
- 默认初始化
- 声明初始化
- 构造块初始化(与声明初始化先后顺序视位置而定)
- 构造器初始化
2.2.和局部变量的区别?
作用域:成员变量在整个类中都有效,局部变量只在定义它的代码块中有效。
初始化:成员变量在new创建对象的时自动初始化,局部变量需手动初始化,否则,编译无法通过。
优先级:当成员变量和局部变量同名时,遵循就近原则,即在代码块中优先使用局部变量。
ps:局部变量是在方法或代码块中定义的变量。
3.方法
3.1.方法的声明
访问修饰符 返回值类型 方法名(参数1,参数2,……){
方法体;
}
说明:
- 访问修饰符:public,protected,默认,private
- 返回值类型:基本类型和引用类型或者void
- 参数:可以没有,也可以有多个
使用方法的注意事项:
- 带返回值的方法,返回的值得类型必须与返回值类型一致或其子类,且只返回一个值;
- 方法能嵌套调用,但是绝不能嵌套定义;
- 不允许把程序的逻辑代码直接写在类中,必须封装到方法里;
3.2.方法的调用
- 不相同类中,需要通过new关键字创建对象,然后通过对象调用方法,匿名可以直接调用方法且只能使用一次;
- 相同类中,自定义方法之间使用this关键字调用,也可以省略this;
- main( )方法调用方法必须先创建对象,所有的静态方法都是这个原则。
3.2.方法的好处
- 代码重用
- 增强可维护性
- 功能的封装
4.参数传递
调用方法时有一个传参的过程。什么是传参?把实参传递给形参,给形参赋值。传参的时候,类型,个数,顺序要保证一致。
4.1.传值和传址
基本类型,传值,不改变原值;引用类型,传址,改变原值。
4.2.可变参数
Java 5.0版本才出现可变参数特性,其底层是数组。
声明
- 访问修饰符 返回值类型方法名(类型 …变量名){方法体}
使用
- 方法中最多只能有一个可变参数,且必须放参数列表末尾;
- 传参方式灵活,可以不传,也可以传多个,还可以传数组,本质上是先将参数转换为数组再使用,所以,与数组参数不构成重载;
- 在方法中可变参数变量与数组参数变量用法一致;
- 可变参参数传参过程中,凡是导致Java编译器有歧义的都无法通过编译。
与数组参数的区别
- 数组可以有多个参数,但是可变参数最多只能有一个;
- 数组只能传一个值,可变参数传参形式灵活,可以不传参,也可传多个参,甚至传入数组;
- 数组可以放在参数列表任何位置,可变参数只能放在参数列表末尾;
- 可变参数与数组参数不构成重载
4.3.main()方法传参
Java虚拟机调用main( ),所以在运行时传入参数,传入方式如下:java 类名 参数1 参数2 参数3…
二、重载和构造
1.什么是重载?为什么要重载?怎么做?
- 定义:通常在同一个类中,多个方法同名但是参数列表不同(类型、个数和顺序)。这些方法就构成重载。
- 作用:方便记忆!
- 使用:方法名保持一致,参数列表必须不同,且重载只与方法名和参数列表有关;传参时涉及到类型转换导致编译器无法判断,编译器就会报错。
2.构造器
2.1.构造器声明方式
访问修饰符 类名(参数){
初始化代码块
}
说明:
- 访问修饰符:public,protected,默认,private
- 名称必须与类名保持一致;
2.1.构造器的作用
使用new关键词调用构造器,作用是,初始化对象,给成员变量分配空间并赋初值。
2.2.构造器的分类
- 默认构造器:未显式声明构造器时编译器自动加上无参构造器,一旦声明编译器就不管了。
- 无参构造器:不管用与不用,建议都显式声明。
- 带参构造器:一般是创建对象时调用给属性赋值。
- 构造器相互之间也构成重载,在构造器中调用其他构造器使用this(参数),且必须放在代码第一行。
2.4.构造块
直接声明在类中,没有任何关键词修饰。作用是初始化成员变量,解决了构造器重载时代码冗余的问题。在构造器之前执行。
2.5.构造器与访问器的区别
- 构造器用于完成对象初始化,访问器用于读写属性值。
- 构造器通过new关键词调用,访问器通过对象调用。
- 构造器一次性初始化多个属性值,访问器只能单独读写。
- 构造器只能执行一致,访问器可以多次调用。
2.6.构造器与普通方法的区别
- 构造器没有返回值,普通方法有返回值
- 构造器通过new关键词调用,普通方法只能通过对象调用
2.7.构造者模式
构造者模式的简单应用:可以在创建对象时链式调用setter访问器初始化,从而缓解参数过多难以记住的问题。
public Flour setType(String type) {
this.type = type;
return this;
}
new Flour().setSoup(true).setType("酸辣面").setWeight(2).check();
三、访问权限
1.封装
1.1.为什么要封装?
数据安全问题,比如年龄属性是由特定范围的,不能随便赋值,所以,赋值是需要加以控制。这中问题需要封装来解决。
1.2.什么是封装?
把数据隐藏起来,使用private等访问权限关键词进行封装,并对外提供公共的访问器,在访问器中加入控制代码,从而保证数据的安全性。
1.3.访问器
public void set属性名(类型 参数){
this.属性名 = 参数名;
}
public 类型 get属性名(){
return 属性值;
}
2.包
2.2.包的声明
格式:package 包名
说明:必须放在文件的第一行
包名规范:
- 字母都小写;
- 包名是唯一的;
- 包具有层次结构;
- 域名反转.部门名.项目名
2.3.包的使用
- 不同包下的类相互访问,需要导入类,导入方式:import 包名.类名; 或者 import 包名.*; 或全类名声明和创建对象。
- 有子包,则必须导入子包的类,仅导入父包,则只能使用父包下的类,不能使用父包下的子包中的类。
- 两个包下的类同名,则需用全类名指明。
2.4.包的好处
- 管理类和接口
- 解决了命名冲突问题
- 提供了更好的封装,保护类和类中的成员
2.5.常见的包
- java.lang: 核心类库System,String等
- java.util: 工具类 集合类
- java.text: 格式化
- java.math: 数学
- java.io: 流
- java.sql: 数据库
- java.net: 网络编程
3.访问修饰符
访问修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | |
默认 | 可以 | 可以 | ||
private | 可以 |
说明:
- 类:public和默认,只有这两个能用。因为对于类,只有包内使用和包外使用两种情况。
- 属性,方法,构造器:四种修饰符都能使用。
4.静态(static)
另一种修饰符,可用于修饰变量、方法、块、类(仅内部类)
4.1.静态变量
特点:
- 属于类的;
- 类加载的时候初始化;
- 不属于对象,但是可以被对象共享(对象能够调用),这也是静态变量的作用。
- 使用方式:类名.变量名
静态变量与实例变量的区别:
- 所有者:静态变量属于类,实例变量属于对象;
- 初始化:静态的在类加载的时候初始化,实例变量只有在new创建对象的时初始化。
- 释放:静态的在类卸载的时候释放(即应用程序结束,生命周期长),实例变量是对象释放了就销毁了。
加载顺序及内存图如下:
- java命令调虚拟机,虚拟机先把主方法所在类的.class文件加载到方法区,加载完了之后会生成Child.class的类对象放在堆里面,然后发现有静态变量,则在方法区的静态区里面开辟一块空间给静态变量,并且初始化为0。接下来,就是执行main方法里面的代码。
4.2.静态方法
static修饰的方法称为静态方法或者类方法。使用简单,不能创建对象,却要实现功能,就可以定义静态方法。
静态方法与实例方法的区别:
- 静态方法中不能出现非静态的成员,而实例方法则没这样的限制。
4.3静态代码块
代码块总结:
- 构造块:作用是初始化对象,构造方法重载时,解决代码冗余问题,创建对象时执行。
- 静态块:作用是初始化类,在类加载时为类中的静态变量开辟空间并赋值。
- 局部代码块:作用是控制局部变量的使用范围和生命周期。
各种代码块执行顺序:
- static块:类加载自动执行
- 构造块:new对象时,自动执行
- 构造器:new 类名()时调用执行
- 局部块:只有调用方法时执行
静态变量初始化顺序:
- 默认初始化
- 声明初始化
- 静态库初始化(2,3需看代码顺序)
4.4.静态导入
导入不同包下的静态成员,格式:import static 包名.类名.静态变量名(方法);
4.5.单例模式:有且仅有一个对象的类
/**
* 饿汉式和懒汉式区别
* 1.饿汉式类加载时,值就有了。懒函数,只有在使用的时候才会赋值。
* 2.多线程:饿汉式安全,懒汉式不安全。
*/
public class Single {
//饿汉式
private static Single instance = new Single();
//必须把构造器声明为private的,所以不能使用默认构造器
private Single(){}
public Single getInstance(){
return instance;
}
}
public class Single {
//懒汉式
private static Single instance = null;
//必须把构造器声明为private的,所以不能使用默认构造器
private Single(){}
public static Single getInstance(){
if (instance == null) {
instance = new Single();
}
return instance;
}
}
四、继承
1.继承
1.1.什么是继承?
- 根据已有的类派生出新类的技术,这就是继承。
- 什么样的类需要扩展子类?类增加了一些独特的属性或功能。
- 继承是类与类之间的关系,当然类与类之间不只这一种关系,比如还有组合关系、实现关系等。
- 什么是组合关系?一个类作为另一个类的成员变量。整体和局部的关系,就是组合关系,是类间的关系。
1.2.继承的优缺点?
- 优点:代码重用和便于维护;缺点:高耦合和破坏了封装
1.3.继承语法:extends关键词
1.4.继承的设计原则?里氏替换原则,即IS-A
1.5.注意事项
- java只支持单继承。
- 子类可以继承父类的成员,也可以有自己独特的成员。
- 受封装的影响,有些成员,子类不能直接调用,但还是被继承下来了。
- 构造器不能继承,每次构造对象都是先执行父类的构造器,再执行自己的构造器。
2.super关键词
与this一样,表示对象,且表示的是当前对象的父类对象。
作用
- 调用父类成员,包括构造器;
- 可以区分同名的子类和父类成员。
调用父类构造器
- 创建子类对象时,一定会先调用父类构造(一直调到Object类的构造为止),然后再调用子类构造。
- 子类构造器中如果没有显式的调用父类构造器,或本类构造,那么编译器一定会分配一个super()。
- 父类中显式定义了构造器,而且只有带参构造,那么子类构造方法中必须显式调用父类带参构造器。
- super() 显式调父类构造器,而且必须放在子类构造器的第一行代码处。
继承的传递性
- 子类可以继承直接父类和间接父类中的成员。
- super关键词不能调用间接父类的成员。
3.方法重写
3.1.什么是重写?
- 子类中的实例方法与父类的实例方法名称相同、参数列表相同以及返回值类型相同,则覆盖了父类中的方法。
3.2.为什要重写?
- 子类需要修改父类的功能;
- 子类需要扩展父类的功能。
3.3.如何重写?
- 参数列表:父类参数擦除与子类相同(什么是擦除?泛型的类型参数在生成字节码时会被删除)
- 返回值类型:可以是父类方法返回值类型的子类型
- 访问权限:不能比父类的低
- 异常处理:不能比父类范围更大
3.4.final(终态)
另一关键字,可修饰类、属性和方法。
修饰类:类不能被继承。下面这些情况一般都使用final修饰:
- 为了类的安全性,不希望被子类继承;
- 类中的方法有复杂的调用关系;
- 是最终版本的类。
方法:不能被重写,所有子类都使用同一版本的方法。
变量:java中用它类定义常量,特点,只能赋值一次,不能再修改。但是引用类型,可以修改属性的值。
常量的命名规范:
- 所有字母都大写
- 多个单词组成,单词之间由下划线连接
final定义常量的作用:
- 数值安全
- 增强可维护性
- 增强可读性
3.5.设计一个可以被继承的类(继承的特点是高耦合)
- 继承的层次关系不要超过3层。
- 最好有详细的文档说明,方法的自用性是什么,重写之后会带来什么影响。
- 要封装:如果对所有用户开发用public;只对子类开放用protected;对子类开放,又不希望子类更改代码,定义为final。
五、抽象类和接口
1.抽象类
1.1.定义
只约定类所具有的抽象行为,而没有具体实现相应的行为。
1.2.语法格式
- abstract class 类名{
- 常量;
- 变量;
- 构造();//不可以创建对象,但是构造方法要用来初始化当前类
- 访问修饰符 abstract 返回类型 方法名();//抽象方法
- 普通方法;
- 静态方法();
- }
1.3.使用场合
- 此类不适合创建对象,每次用的都是子类的对象。比如动物类,交通工具类等。
- 为所有子类提供一个模板。
1.4.使用注意
- 抽象类不能创建对象
- 必须通过子类继承使用
- 普通子类必须实现抽象父类的所有抽象方法(抽象子类除外)
- 构造器不能是抽象的
- abstract 不能与private、static、final一起连用。(static是类级别的,可以直接通过类名调用,这是失去了抽象类的意义)。
- 抽象方法可以定义也可以不定义。
2.接口
2.1.定义
是一组功能的封装,是一组公共的规则。
2.2.语法格式
访问修饰符 interface 接口名{ //所有的成员都是public的,不管指不指明。
- 常量;
- 默认方法;
- 抽象方法;
- 静态方法;
- 静态内部类型;
}
说明:
- 常量和默认方法:可以在子接口或实现类中直接使用
- 默认方法:必须加上default修饰
- 静态方法:子接口和实现类是不能继承
- 静态内部类型包括:静态内部类,静态接口,静态枚举类型
2.3.使用注意
- 接口中是不能定义构造器的,更不能创建对象
- 由实现类实现接口,普通的实现类必须实现接口中的所有抽象方法(抽象实现类除外)
- 实现类可以实现多个接口中的功能
- 接口可以继承接口,而且可以多继承。
- 接口中的成员都是public的,抽象方法都是abstract的,常量都是public static final的
2.4.实现多个接口时,有相同方法名如何处理?
- 静态方法:用接口名区分
- 默认方法:实现类需要重写方法,在方法体中,使用这个格式调用:Ia.super.df(); 或 Ib.super.df();
- 抽象方法:重写两个方法中任意一个即可或用匿名内部类分别实现两个同名的方法。
2.5.接口中默认方法解决了什么问题?
- 遇到问题:接口一旦发布,不予许更改,一旦更改,所有实现类都必须改变。
- 解决方式:加入默认方法,则可直接正常使用,不会影响任何实现类,便于接口的功能升级。
2.6.接口和抽象类的异同点
相同:
- 都不能创建对象
- 都存在抽象方法
- 都是使用子类或实现类去继承或实现类使用
- 普通的子类和实现类必须要实现二者中的抽象方法(抽象子类或抽象实现类除外)
不同:
- 子类只能继承一个抽象类,但实现类可以实现多个接口
- 类是单一继承,接口可以多继承
-
接口本质就是一份协议或者约定,所有参与者都得遵守。同一应用程序中接口是用来降低耦合性的。不同的应用程序中接口时连接的桥梁(京东提供银行的功能),而抽象类更严格的说是一份模板。
-
注:设计程序的时候,最上层是接口,下面一层是抽象类,最低层是是实现类。
3.多态
3.1.定义
- 所谓多态,起始是同一种物质的多种存在状态。
- 在程序中,多态是同一种引用类型使用不同实例执行不同的操作。
3.2.多态的两个特征
- 重写
- 父类引用指向子类的对象,或接口指向实现类的对象。
- 注:子类或实现类中独特的属性或方法无法调用,否则编译不通过。
3.3.类型转换
- 向上类型转换,指的是子类类型自动转换为父类类型。
- 向下类型转换,指的是父类类型强制类型转换为子类类型。
- 注:instanceof运算符,运算某个对象是否是类或者接口类型,若是,则结果为true,否则,结果为false。
4.类与类之间的关系
4.1.UML建模语言
4.2.关系分类
- 泛化:就是继承关系
- 实现:接口和实现类的关系
- 依赖:就是一种使用的关系,被依赖的作为局部变量(参数)来体现。比如饲养员依赖动物和事物,那么动物和食物就作为饲养方法的两个参数。
- 关联:是一种拥有的关系。
4.3.关联关系有分为3种情况
- 一对一:一个实体对应一个实体,比如汽车和车位。
- 一对多:一个实体对应多个实体,比如一个学员对应多门课程。
- 多对多:多个实体对应对个实体,比如一个老师对应多个学员,一个学员对应多个老师。
- 有一种特殊的关联:强关联,称为聚集或集合,体现的是整体和局部的关系,局部离开了整体可以独立存在,比如计算机是整体,键盘和鼠标可以独立存在。语法上都是以成员变量来体现的。
- 对于聚集来说,有一种特殊的聚集(强聚集或强聚合),即组合,局部离开了整体不能独立存在。
六、补充内容
1.类名规范:服从帕斯卡命名法,即单词首字母大写。
2.每个对象在内存中都是独立的空间,相互之间不产生任何影响。
3.this关键词
表示当前对象,可以调用当前类的成员。
4.只有在类,属性,方法上加文档注释,才能被javadoc命令识别并产生帮助信息。
5.一个文件中编写多个类
- 有且仅有一个类是public修饰的;
- public修饰的类必须是主类;
- 被public修饰的类的类名必须与文件名一致;
- 注:每个类都会被编译成一个单独的字节码文件
6.this关键词的使用
- this用于当前类的成员;
- this(参数)用于调用其他构造方法,且必须是当前构造方法的第一行代码。
- 返回当前对象的方式:return this; //这么用时正确的
7.API值Math类
常用方法:
- double ceil(double d);//大于等于指定参数的最小整数
- double floor(double d);//小于等于指定参数的最大整数
- long round(double d);//四舍五入
- double pow(double a , double b);//a是底数,b是指数
- double random();//随机数[0.0 , 1.0),左闭右开
8.随机数
方法一:使用Math类
(int)(Math.random()*(最大值-最小值+1)+最小值)
方法二:使用随机数类Random
//参数1,表示随机种子,跟随机算法有关。如果随机种子相同,在相同时间参数的随机数是一样的。
Random r1 = new Random(1);
Random r2 = new Random(1);
System.out.println(r1.nextDouble());
System.out.println(r2.nextDouble());//因为设置的随机种子,所以,这两个随机数一样
r2.nextInt();//产生 [0 , 上限)范围的随机数
r2.nextInt(45);//产生[0 , 45)范围的随机数
9.Object类:所有的类的直接或间接父类
finalize():垃圾回收器释放对象之前调用,用于释放资源或者给对象恢复引用。
equals():比较两个对象是否相等,地址是否相等。
toString(): 对象的字符串描述信息。在用println或print输出对象名时,会自动隐式调用对象的toString()
哈希:对数据的唯一标识。
哈希值:把一些数据用哈希算法变换成固定的数值,这个数值就是哈希值。
- 可以作为文件或数据的唯一标识;
- 节省系统开销;(备份文件,直接存储算出来的哈希值即可)
- 加密:哈希算法的值一般是没法看得懂得。
哈希算法(常见的哈希算法)
- 直接寻址法:直接把数据取出来,不做任何加工,就作为哈希值。
- 数字分析法:用数字中不一样的部分作为哈希值。
- 平方取中法:把数字平方的结果,取中间部分的几个单数取出来作为哈希值。
- 折叠法:(数值很大的情况)把数字拆分成几组,每组3-4个数字,然后再做相同位数的求和,结果作为哈希值。
- 随机数法:Random类,以数值作为上线去随机值,比如Random.nextInt(786)结果作为哈希值。
- 除留取余法:(百度下)数值 % 某个数 得出的余数作为哈希值,其中某个数。???