Java面向对象第一天
一、序言
1、分割
2、类型转换
二、类和对象
1、编写一个类
2、使用类的对象
3、修改后的代码
解决了分割和类型转换的问题
4、概念
是一种数据类型是对象的模板
5、面向对象解决一类问题OO 面向对象
OOA 面向对象分析 分析项目中参与的人和物
OOD 面向对象设计 将人和物的特点设计出来(属性和行为)
OOP 面向对象编程 用高级语言描述设计的内容将对象的属性和行为抽象为类。
6、封装
暴露简单,封装复杂体现方式:
将所有属性私有化,只能通过set和get方法对属性进行操作。(可以在set和get方法中写一些逻辑(不是必须的))
使用
Java面向对象第二天
一、构造方法
1、功能
对对象数据进行初始化
简化对象数据初始化的操作
每个类声明时,都有一个隐式无参的构造方法
Emp.java
里面没有声明构造方法
在测试类中可以使用无参构造方法
构造方法没有返回类型的声明
构造方法名称是固定和类名一致(大小写一致)
如果声明了有参构造方法,默认隐式的无参构造方法就没有了,如果需要使用,则手动声明
Emp.java
手动声明了有参构造方法
测试类中就不能是用默认无参的构造方法
构造方法与set方法的区别
构造方法是用来初始化数据的,只能调用一次。
set方法是用来修改数据的,可以重复调用。
二、成员方法
set和get
1、方法的分类(按照参数和返回值)
a、无参无返回值
b、有参无返回值
c、无参有返回值
d、有参有返回值
改写项目
将项目中的功能(任务)改成方法(无参无返回值的方法)
2、static方法
没有static的方法,需要通过对象调用
下面的方法和对象有关,需要先实例化对象,才能使用
测试代码
有static的方法,可以通过类或者对象调用(不建议使用对象调用)和对象无关,直接使用类名调用,方法的数据从参数传递
测试代码
三、方法重载overload
1、概念
在一个类中有多个方法同名,不同参数列表(类型不同、个数不同、位置不同)根据传入的参数类型和个数决定调用哪一个方法
测试
四、可变参数方法
1、语法结构
2、调用
3、注意
当方法除了可变参数以外还有其他参数,其他参数放在可变参数的前面正确的写法
错误的写法
Java面向对象第三天
一、回顾
类
一种数据类型
是对象的模板(对对象的抽象)属性和行为
封装:
将属性私有化,每个属性都有对应的set和get方法,set方法修改内存空间的数据,get方法获得内存空间的数据。
构造方法:
方法名与类名一致没有返回声明
对内存数据进行初始化成员方法(没有static)
通过对象名调用
public void printInfo(){
}
方法分类(不包含构造方法)无参无返回值
public void methodName(){
}
有参无返回值
public void methodName(Type param1,...){
}
无参有返回值
public Type methodName(){
return 和Type类型相同的数据;
}
有参有返回值
public Type methodName(Type param1,...){
return 和Type类型相同的数据;
}
可变参数方法
public Type methodName(Type ... param1){ return 和Type类型相同的数据;
}
方法重载
overload
在一个类中,有多个方法同名不同参数列表(个数不同、类型不同、位置不同)
对象
Emp emp = new Emp();
加载Emp.class到方法区(元数据区)在栈中声明Emp的变量
在堆中按照Emp.class的内容生成对象(属性是放到对象中,方法只放了方法名,根据地址找到方法在
Emp.class的位置)
访问成员(属性和方法)
二、在员工管理系统中应用
1、代码结构以前的结构:Emp.java 实体类
声明员工的属性和行为属性
构造方法(无参和全参)
setter&getter
获得信息
EmpSystem.java
声明存储员工的数组
Emp[] emps = {};
将员工新增、员工修改、员工离职、查询所有员工变成了无参无返回值的方法
main方法
生成EmpSystem的对象
循环菜单
获得用户选择的任务通过swtich运行任务
通过EmpSystem的对象调用对应的方法
三、代码结构
1、Goods类
2、GoodsDAO
import java.util.Arrays;
public class GoodsDAO {
private Goods[] goodsArray = {};
/**
- empAdd
- 添加商品的方法
- @param obj
- @return*/
public boolean save(Goods obj) {
int index = getIndexById(obj.getId()); if(index>=0) {
return false; - 商品修改方法
- @param obj
- @return*/
public boolean update(Goods obj) {
int index = getIndexById(obj.getId()); if(index>=0) {
goodsArray[index] = obj; return true; - 根据id在数组查找索引,如果找不到返回-1
- @param id
- @return*/
private int getIndexById(int id) {
for (int i = 0; i < goodsArray.length; i++) { if(id==goodsArray[i].getId()) {
return i;
}
}
return -1;
}
/** - 删除商品
- @param id
- @return*/
public boolean delete(int id) { int index = getIndexById(id); if(index>=0) {
goodsArray[index] = goodsArray[goodsArray.length-1]; goodsArray = Arrays.copyOf(goodsArray, goodsArray.length-1); return true; - 根据编号查询商品
}
/**
}
goodsArray = Arrays.copyOf(goodsArray, goodsArray.length+1); goodsArray[goodsArray.length-1] = obj;
return true;
}
/**
}
return false;
}
/**
}
return false;
3、GoodsView
4、App
Java面向对象第四天
类
属性
行为(方法)
是一种数据类型(引用类型的一种)是对象的模板
对象
访问类中声明的成员(属性和行为)对象名.属性
对象名.访问
面向对象的三个特性之一封装
封装复杂,暴露简单
在类中,将属性私有化,通过setter和getter进行访问。
private
构造方法
全参和无参方法种类
方法重载
在一个类中,有多个方法同名不同参数列表(类型不同、个数不同、位置不同)
员工管理系统实体类
DAO类(数据操作对象)View类
启动程序
1、概念
package
包的功能:
a、方便维护代码
b、可以在一个项目中存在同名类
2、命名规范
a、包名全小写
b、分成基础的三部分
公司的性质.公司的名称.代码的分类
com.woniuxy.entity Emp.java
com.woniuxy.dao
EmpDAO.java com.woniuxy.view EmpView.java
com.woniuxy App.java
3、包的使用
a、声明当前类在哪个包下
在类的最上面声明类所在的包
b、将不同包的类引入到当前类中使用
引入的代码在package和类声明之间
4、注意
不同包下有同名的类?
5、默认引入包
将java.lang包下所有类自动引入,不需要手动引入。
private 私有
default 默认的(没有修饰符)
protected 受保护的
public 公有
本类 | 同包 | 不同包子类 | 不同包其他类 | |
public | y | y | y | y |
protected | y | y | y | n |
default | y | y | n | n |
private | y | n | n | n |
本类
同包
不同包的子类
不同包其他类
常用的访问范围private和public
1、功能:
提高代码的重用性
2、编写方式:
将项目中的类再进行归纳,将有相同属性和功能的类提取放入父类中,需满足(is a关系),子类中就不需要重复声明属性和功能,通过父类继承。
extends
子类extends 父类子类subclass
父类superclass baseclass
3、缺点:
高耦合
父类发生变化,直接影响子类。
4、例子
在父类中编写公有的属性和方法
在子类中继承父类,可以继承父类中的属性和方法只需要编写自己特有的属性和方法即可。
5、类继承的特点
单继承:一个类只能有一个父类
6、万物皆对象
所有类都默认继承Object类
java.lang.Object
7、调用父类构造方法
a、当调用子类无参构造方法时,默认调动父类无参构造方法
运行结果
b、在子类中调用构造方法时,没有显式调用父类构造方法,默认调用父类无参构造方法
运行结果
c、调用子类全参构造方法,一般会将所有属性都传入(包括父类的),显式调用父类的全参构造方法处理父类的属性,子类再处理子类的属性
运行结果
override
子类继承父类,父类中的方法不再适用,可以选择在子类中重写该方法。
1、编写要求:
a、子类中该方法的访问范围应大于等于父类该方法b、返回类型
父类是void,子类应是void
错误的
父类是基本类型,子类必须一致
父类是引用类型,子类类型需小于等于父类的
c、方法名和参数列表必须一致
2、重写Object的方法
a、toString
重写输出对象的内容
b、equals
重写两个对象比较的功能(所有内容一致就返回真)
六、final
1、修饰属性
变量变常量,不能被修改
2、修饰类
变成最终类,不能被继承最终类A
编写B类继承A类
3、修饰方法
变成最终方法,不能被重写
这时D类中报错
Java面向对象第五天
一、static
1、修饰属性
变成静态属性,所有对象都访问同一个空间(类加载区(元数据区))
可以通过类名直接调用,也可以使用对象名调用(不建议)。
2、代码块(初始化块)
每次实例化对象,调用构造方法前执行。
3、修饰代码块
静态块:只在类加载时执行一次
4、修饰方法
静态方法:通过类名调用,也可以通过对象名调用(不建议)
注意:
静态块只在类加载时执行一次
代码块,每次实例化对象时都会执行一次
注意2:
按照存在先后顺序
静态块和静态方法中不能使用非静态属性
父类
子类
1、这时要new一个Emp的对象2、发现Emp类有一个父类
3、先加载父类
a、将Person.class加载到元数据区
b、给Person中的static属性开空间赋初始值c、调用Person中的static块
4、加载子类
a、将Emp.class加载到元数据区
b、给Emp中的static属性开空间赋初始值c、调用Emp中的static块
5、调用父类的代码块
6、调用父类的构造方法
7、调用子类的代码块
8、调用子类的构造方法
1、抽象方法
没有方法体的方法,使用abstract声明,没有大括号,直接分号结束
2、抽象类
1、类中的方法无法编写方法体,则要变成抽象方法
2、有抽象方法的类要变成抽象类
3、抽象类可以没有抽象方法
4、抽象类不能实例化对象
5、抽象类必须被继承
6、子类需重写父类中的抽象方法
7、如果不重写,该类也需声明成抽象类
1、interface
是一个特殊的抽象类,所有方法都是抽象方法(1.8之前),可以编写方法体了(增加了default和static方法)定义规则
2、继承关系
类与类是继承extends 单继承
类与接口是实现implements 多实现接口与接口是继承extends 多继承接口
实现类
1、向上转型
子类对象转成父类,可以直接转,但是只能使用父类中的成员
2、向下转型
父类对象转成子类,有风险。
先要判断对象的类型,才能进行转换(强制转)父类
子类
测试
instanceof 判断前面的对象是否为后面的类型,结果是boolean类型在项目中的应用
接口
实现类一
实现类二
测试代码
1、概念
一个事物多种形态
2、例子
人演奏乐器
Person.java
声明乐器类(抽象类),包含一个抽象方法(演奏),也可以写成一个接口要求子类或者实现类重写play方法
定义具体类乐器类钢琴
小提琴
唢呐
测试:
雇佣音乐家Person p = new Person();
购买三个乐器
Piano Violin Suona
1、单例的三个步骤
a、私有化构造方法(private)
b、在本类中声明自己的实例(private static)
c、在本类中编写一个方法来获得实例(public static)
2、饿汉式
3、懒汉式
集合
Collection List
ArrayList
LinkedList Vector
Stack
Set
HashSet LinkedHashSet TreeSet
Map
HashMap
Collections
sort(Collection c) 使用内置比较器
sort(Collection c,Comparator c2); 使用外置比较器
二、List
0、概念
有序(和添加顺序一致),可以有重复值、可以通过索引访问
1、ArrayList
动态数组
底层是一个对象数组Object[] elementData
扩容机制:每次增长一半(使用的是右移位运算)
add方法
E e 在没有操作之前,这个E就是Object
功能:将参数放入对象数组中,返回boolean表示是否成功
size方法
功能:获得对象数组中元素的个数,既是索引size
get方法
功能:根据索引获得数组中的元素这个E还是Object
remove方法
功能:根据索引移除数组中的元素
样例
2、LinkedList
底层是双向链表
相对ArrayList的特点:增删快,查询慢
1、概念
动态类型(只能使用引用数据类型)自定义的集合类
用尖括号包含了一个动态类型
泛型可以随便写,但是要遵循规范:单词首字母大写
在指定泛型后,E被替换成指定的类型
1、概念
所有基本数据类型都有一个对应的包装类型
2、基本类型和包装类型的对应
基本类型 | 包装类型 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
3、功能:
a、可以在泛型中使用
b、可以进行字符串向基本类型的转换
c、判空
在项目中实现动态修改功能
Emp.java将所有基本类型都改成包装类型
EmpView.java
EmpDAOImpl.java
五、Set
1、概念
无序(和添加顺序无关),不能添加重复数据,不能通过索引访问
2、HashSet
add()
size()
3、String
a、char charAt(int index) b、int length()
c、char[] toCharArray()
4、例子
5、TreeSet a、功能:排序b、例子
c、冒泡排序
冒泡排序的英文Bubble Sort,是一种最基础的交换排序。之所以叫做冒泡排序,因为每一个元素都可以像小气泡一样,根据自身大小一点一点向数组的一侧移动。
原理
冒泡排序的原理:
每一趟只能确定将一个数归位。即第一趟只能确定将末位上的数归位,第二趟只能将倒数第2 位上的数归位,依次类推下去。如果有n 个数进行排序,只需将n-1 个数归位,也就是要进行n-1 趟操作。
而“每一趟” 都需要从第一位开始进行相邻的两个数的比较,将较大的数放后面,比较完毕之后向后挪一位继续比较下面两个相邻的两个数大小关系,重复此步骤,直到最后一个还没归位的数。
d、内置比较器
特点:只能做一种排序规则排序步骤
i、让要排序的类实现Compareable接口
ii、重写compareTo方法(定义排序规则)
iii、属性比较(当前对象的属性和参数对象的属性比较),大于返回正数就是升序;返回的负数就是降序。
e、工具类的排序功能
Collections是集合的工具类
sort方法(将集合内容进行排序(按照内置比较器排序))模拟了该方法
测试功能
f、外置比较器
Comparator
可以定义多个比较规则步骤:
i、编写一个类实现Comparator接口
ii、重写方法compare(Object obj,Object obj) iii、编写比较规则
升序规则
降序规则
iv、使用工具类的排序方法(两个参数:第一个参数是要排序的集合,第二个参数比较器类的对象)Collections.sort(list,);
上面的代码会对原集合进行修改给出两个方案:
1、显示所有时,按照id升序排序IdAsc.java
调用时,加入排序代码
2、排序时,选择使用copy后的集合操作,不影响原集合
1、普通内部类
2、静态内部类
3、方法内部类
4、匿名内部类
一个类只使用一次,可以声明成匿名内部类
七、lambda表达式
简化匿名内部类的编写
-> goes to
1、省略实例化对象的代码
2、要求接口的中抽象方法只有一个
3、方法参数类型可以省略(接口声明时添加泛型了)
4、如果方法体只有一行代码,可以去掉大括号
5、如果这行语句是return语句,可以去掉return关键字
八、Map
0、特点
存放键值对
1、HashMap
a、特点:
存放键值对 key不能重复key可以为null value可以重复
key和value可以是任意类型的数据
b、方法:
Object put(Object key,Object value);将键值放入map Object get(Object key) 通过键获得值
Set keySet();获得所有的键
boolean containsKey(Object key)判断key是否在map中存在
boolean containsValue(Object value);判断value是否在map中存在Collection values()获得map中所有的值
Set entrySet()获得所有的键值对
remove(Object key);按照key将map中对应的键值对移除
c、例子:
练习:
d、map遍历的方式
e、底层
HashMap的底层是数组+链表+红黑树
数组默认长度为16,扩容因子是0.75,每次扩容1倍。
当桶位(数组长度)>=64,桶位中链表元素>=8,将链表变成红黑树当链表元素<=6,将红黑树转成链表
HashMap put流程:
- 根据键的hash码(调用键的hashcode方法)进行哈希运算(hash()),得到一个整数哈希值(不是数组的下标位置)`
- 判断哈希表是否为空或者长度是否为0,如果是,要对数组进行初始化(初始化为16),如果否,进入3`
- 根据1得到的哈希值计算数组索引(与运算(n - 1) & hash),得到一个和数组存储位置匹配的索引i(确定到桶的位置)`
- 判断i号位置是否为null,如果null,就将键和值封装为一个Entry(Node)类型的对象进行插入,如果不为null,进入5`
- 判断key是否存在(使用equals进行判断,在一个桶里面判断),如果存在,覆盖原有的值,如果不存在,进入6`
- 判断i号位置是否为一个树结构,如果是一个树结构,在树中进行插入,如果不是树结构,进入7`
- 为链表结构,对链表进行遍历,判断key是否存在,存在就覆盖,不存在就在链表中插入新的节点`
- 链表中插入新节点后,如果i号位置的元素个数大于等于8且hash表的长度大于等于64,i号位置的所有元素转换为树结构,反之,新节点正常插入结束`
- size++`
- 判断是否要进行扩容,如果需要扩容,就执行Resize()进行扩容`
- 结束`
4、HashMap注意事项
为什么HashMap的长度为什么要设计成2的n次方?
提高效率:为了方便将去余运算转换为位运算hash%长度== (n - 1) & hash
尽量让计算到的位置均匀 为什么设计扩容因子
为了减少一个桶里元素碰撞的概率,本质就是不要让一个桶中的元素个数太多 根据key怎么找到值的(get(key))?
根据key的哈希码先找到桶的位置,然后再在一个桶中用equals方法进行比对键,找到对应的节点,获取其值。
为什么使用hash码相关的集合的时候,重写equals方法的时候建议也重写hashCode方法
如果equals返回true.但是哈希码不一样,有可能会放到不同的桶中,不同的桶中就存在了键重复的元素了,有漏洞,最终目的是为了让equals返回true的两个对象能放到一个桶中,保证键不重复
2、TreeMap
a、功能:
有排序功能
b、可以使用比较器对对象进行排序(只能对key进行排序)
3、Hashtable
例子
使用上和HashMap的方法基本一致。
HashMap和Hashtable的区别:
根据hash码计算存储位置的过程和算法是不同的(hashMap最后进行位运算,hashtable最后进行取余的运算)。
Hashtable不能放入null键,null值,但是HashMap可以放入null键null值 Hashtable初始的默认长度是11,HashMap是16.
Hashtable线程安全,效率低,HashMap线程不安全,效率高
扩容方式不同,HashMap扩容为原来的2倍,Hashtable扩容为原来的二倍加1 int** newCapacity = (oldCapacity << 1) + 1;
九、日期类1、Date
a、构造方法
b、成员方法
c、例子
d、年龄比较
2、SimpleDateFormat
日期格式化类
a、功能:
字符串和日期对象相互转换
b、构造方法
c、成员方法
3、修改项目中的代码
a、修改实体类
将int age改成Date birth
重新生成Set、get和构造方法
将输出生日对象改成输出转换后的字符串
b、改DAO实现类
改了初始化数据(构造方法变了)
改了动态修改,把判断年龄改成判断生日
c、修改View类
改了按年龄升序排序的比较器
修改员工添加和员工修改方法