思想
面向过程的程序设计思想 process-oriented-programming POP
焦点: 过程->操作数据的步骤 实现代码重复出现, 抽取为一个函数
代码结构: 以函数为组织单位
执行者思维
面向对象的程序设计思想 object oriented programming OOP
焦点: 类 参照现实中事物 将事物属性特征行为 抽象出来 用类来表示
代码结构: 以类为组织单位
设计者思维
面向对象 面向过程 相辅相成
类与对象
- 类 => 抽象概念的物 属性 行为
- 对象 => 实实在在的某个物
内存结构
public static void main (String [] arg){
Person p1=new Person ();
p1.name="杰克";
p1.age=24;
}
- 方法区: 存放类的模板
类的成员-属性
内存分配
对象属性: 随着对象的创建,存储在堆空间中 随着对象的创建而创建,消亡而消亡
有默认初始值
局部变量: 存储在栈空间中 随着方法对应的栈帧入栈,局部变量在栈中分配,栈帧出栈,则消亡
无默认值 须显式赋值
类的成员-方法
- 类/对象 行为特征的抽象 完成某个功能操作
- JAVA 中类方法 不调用不执行
public static void main(String[] args) {
Person p1 = new Person();
p1.sleep(6)
}
Student[] stus=new Student[3];
stus[0] = new Student();
stus[0].id = 10;
stus[0].score = 78;
方法重载
概括
同一类 同名方法 参数列表不同 (个数 , 类型) 多个方法.彼此之间构成方法重构
注意: 重载与形参名, 权限修饰符 返回值类型都没有关系
- 编译器如何确定调用某个具体方法?
方法名 -> 确定一波重载方法(不同形参列表) -> 具体方法
可变个数形参 方法
// 注意: 可变参数 须声明在形参列表的最后 可变个数确定
public void print(int ... nums){}
方法的值传递机制
- 基本数据类型 值传递
int m=10;
int n=m;
m++;
// m=11 n=10
- 引用数据类型 地址传递 new
实参给形参赋值
基本数据类型传值
public static void main(String[] args) {
int m = 10;
int n = 20;
test.swap(m,n);
}
public void swap(int m, int n){
int temp = m;
m = n;
n = temp;
}
引用类型传值
class Date {
int n;
int m;
}
class Test {
public static void main(String [] args){
Test test = new Test();
Date date = new Date();
date.m = 10;
date.n =20;
test.swap(date);
}
pubilc void swap(Date date){
int temp = date.m;
date.m=date.n;
date.n=temp;
}
}
递归
-
自己调用自己的方法 耗内存
-
计算 n!
public int getMul(int n){
if(n == 1) {
return 1;
} else {
return n * getMul(n-1);
}
}
关键字 package import
package : 用于指明该文件中定义的类,接口 等结构所在的包
import : 告诉编译器到哪里去寻找这个类
//全类名引用
java.sql.Date date = new java.sql.Date(12315L);
封装性
因: 把该隐藏的隐藏起来 该暴露的暴露出来
java规定4种权限修饰符 private 缺省 protected public 体现-> 当修饰类及类的内部成员被调用时 体现可见性大小
理论上:
高内聚: 类的内部数据操作细节自己完成 不允许外部干涉 (java程序通常以类的形态呈现,相关的功能封装到方法中)
低耦合 仅暴露少量的方法给外部使用, 尽量方便外部调用 (给相关的类,方法设置权限,把该隐藏的隐藏起来,该暴露的暴露出来)
- ps: 其他包的子类: 不同包通过继承获得关系
应用
- 场景一: 私有化类的属性 提供公共的get和set方法 set中对属性的判定修改 get 获取
- 场景二: 将类中不需要对外暴露的方法,设置为private
- 场景三: 单例模式中构造器private 避免在类的外部创建实例
构造器 constructor
- 格式: 权限修饰符 类名(形参列表) {}
Person p1 = new Person();
//系统默认提供空参构造器 权限跟类一致 类中显示声明构造器 系统不再提供默认构造器
Person()=> 构造器 public Person(){}
<init> 方法
- 在Java中,
<init>不是方法或关键字,而是JVM为每个类生成的构造方法的名称。构造方法用于初始化新创建的对象,并且必须与类同名且无返回类型。
JavaBean
标准java类 java语言写成的可重用组件
- 类公共
- 无参公共构造器
- 有属性,对应的get,set
UML类图 unified modeling Language
关键字 this
-
this => 当前对象
属性与形参同名 this.属性 区分属性与形参
调用构造器 => this();
继承性 inheritance
class Person {}
class Student extends Person {}
继承后 => 子类继承父类 调用父类构造器 -> 子类获取到父类中声明的所有属性和方法 private 须get set 子类不可以直接调用
Java中声明的类,默认继承于 Java.lang.Object
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
总结
方法重写 overwrite/override
- 子类对父类继承过来的方法进行覆盖
//重写 Object=>equals 方法
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof Teacher) {
Teacher teacher= (Teacher) o;
return this.age==teacher.age && this.name.equals(teacher.name);
}
return false;
}
关键字 super
- super 父类的 (继承中)
//方法
super.eat()
//构造器
super(形参列表)
子类对象实例化全过程
子类构造器创建对象时, 子类构造器一定会直接或间接的调用到其父类的构造器,直到Object类中构造器为止
正因调用父类的构造器 将父类中声明的属性方法加载到内存中供子类对象使用
-
创建子类的对象时,内存中到底有几个对象?
一个对象,即为当前new后面构造器对应的类的对象
多态性
使用前提 1.继承 2. 方法的重写 理解: 一个事物的多种形态 方法的多样
//子类的对象赋给父类引用
//针对创建的对象 内存中加载了Man
Person p2 = new Man();
// 虚拟方法调用 编译时 认为方法是父类的类型方法
// 执行时 实际执行的是子类重写父类的方法
p2.eat();
//ps: 属性不适用
Person id=1001
Man id =1002
p2.id => 1001
多态 多用于:
public void adopt(Animal animal) {
animal.eat();
}
// Animal animal = new Dog();
test.adopt(new Dog);
多态 符合 开闭原则 open closed principle 扩展开放 修改关闭
向下转型
// 父类引用 针对创建的对象 内存中加载了Man中特有方法+属性 p2不可以直接调用
Person p2 = new Man();
//向下转型 m1 可调用Man中特有方法+属性
Man m1 = (Man) p2;
// a instanceof A/superA 判断对象a是否是类A/A的父类的实例
if(p2 instanceof Man) => true
总结
Object
类 java.lang.Object 是类层次结构的根类 没有声明属性
equals()
// Object中定义 比较两个对象是否指向了堆空间中同一个对象实体
public boolean equals(Object obj) {
return (this == obj);
}
//String,File,Date 或 包装类 重写equals()方法 比较实体内容是否相等
//String中定义
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
== 和 equals() 区别
- ==
- 基本数据类型 : 判断数据值是否相等
char c1 = 'A';
int i1 = 65;
c1 == i1 => true
- 引用数据类型 : 两个引用变量地址值是否相等
-
equals 方法
引用数据类型 : 对类来说 重写equals() 与 不重写equals() 区别
toString()
//Object类中 toString() 定义
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 子类使用说明
// 自定义类 没有重写Object类的toString() 默认返回当前对象地址值
// String File Date /包装类 重写toString() 返回当前对象实体内容
/**
* String 中 toString()方法
* This object (which is already a string!) is itself returned.
*
* @return the string itself.
**/
public String toString() {
return this;
}
//自定义类 toString() 重写
@Override
public String toString() {
return "Teacher{" +
"age=" + age +
", name='" + name + ''' +
'}';
}
关键字 static
由来:
- 某些特定的数据在内存空间里只有一份 共享
- 有些属性/方法的调用者和当前类的对象无关 => 类属性 类方法
静态变量: 类中的属性使用static进行修饰
静态变量 与 实例变量 (方法类似)
个数: 静态变量 内存空间只有一份 共享 实例变量: 每个实例都保存一份实例变量
内存位置: 静态变量 存放堆空间 实例变量 存放堆空间对象实体中
加载时机:
静态变量 随类加载而加载 类卸载而消亡
实例变量 随对象创建而创建 对象消亡而消亡
内存解析
class Person {
String name;
int age;
static String nation;
}
public static void main(String[] args) {
Person c1 = new Person();
c1.name = "姚明";
c1.age = 42;
Person.nation = "中国"; //或者 c1.nation = "中国";
}
单例模式 singleton
采取一定方法保证在整个软件系统中 对某个类 只存在一个对象实例 该类只供一个取得其对象实例的方法
饿汉式
立即加载 类加载 -> 唯一实例就创建 线程安全 内存占用时间长 例: java.lang.Runtime 类
class Bank {
private Bank(){}
private static Bank instance = new Bank();
public static Bank getInstance(){
return instance;
}
}
懒加载
延迟加载 使用时,创建 省内存空间
class Bank {
private Bank(){}
private static Bank instance = null;
public static Bank getInstance(){
if(instance == null) {
// 存在同时创建实例的可能 线程不安全
instance = new Bank();
}
return instance;
}
}
类的成员-代码块
// 初始化类或对象信息
// 可static 修饰 静态代码块 初始化类信息
static {
...
}
//{} 非静态代码块
{
...
}
类的非静态属性 (实例变量) 赋值
- 默认初始化 int i;
- 显式初始化 int i = 1; / 5. 代码块中初始化 { i = 1; }
- 构造器中初始化 public Test() { i = 1; }
- 有对象后,对象赋值 test.i=1;
先->后 顺序 1 -> 2/5 -> 3 -> 4
关键字 final
final 最终的
修饰类 表示 此类不能被继承
修饰方法 此方法不能被重写
修饰变量 常量 一旦赋值,不可更改
final + static 全局常量
抽象类 和 抽象方法
abstract class Life{
int isLife;
/**
* 吃东西
*/
public abstract void eat();
}
模板方法 - 设计模式
应用: 抽象类作为多个子类的通用模板
接口 interface
本质 : 标准 规范 定制后大家都遵守 interface
- 属性 默认 public static final
- 方法 默认 public abstract
| 类 | 接口 |
|---|---|
| 单继承 一父 | 可多继承接口 |
| 多实现 多接口 |
interface A{
}
interface B {
}
interface C extends A ,B{
}
class Test implements A ,B{
}
public class Teacher extends Person implements Eat , Look{
}
//接口多态性
//接口 实现类对象
Usb usb = new Printer();
jdk8 和 jdk9 接口方法新特性
jdk 8 之前 抽象方法 public abstract
jdk 8 可 声明静态方法(只可接口使用) 默认方法
jdk 9 可 声明私有方法
//默认方法
default void method() {
...
}
//实现类调用
classA.super.method();
抽象类与接口 对比
类的成员-内部类
- 将一个类A(内部类)定义在一个类B(外部类)里面
例子 1. Thread 类的内部 state类 线程生命周期 2. HashMap 类声明Node类 表封装的key和value
class Person {
static class Eat{}
class Work{}
}
//使用
new Person.Eat();
new Person().new work();
匿名类使用
//提供接口 匿名实现类的匿名对象
new Comparable(){
@Override
public int compareTo(Object o) {
System.out.println("你好");
return 0;
}
}.compareTo(person); //对实现方法的使用
枚举类
针对于某个类 其实例是确定个数的
interface Info {
/**
* 展示
*/
void show();
}
public enum Season implements Info{
//默认修饰 public static final
// 在实例中 重写方法 执行不同方法
//使用 Season.SPRING.show();
SPRING("春天") {
@Override
public void show() {
System.out.println("春天到了");
}
},
AUTUMN("秋天") {
@Override
public void show() {
System.out.println("秋天到了");
}
}
;
private final String name;
/**
* 默认private 修饰
* @param name
*/
Season(String name) {
this.name = name;
}
/**
* 公共方法 重写
*/
// @Override
// public void show() {
// System.out.println("学习时间到");
// }
}
annotation注解
- 被编译器或其他程序读取,做出相应的处理
// 例
@Transactional
//元注解 : 对现在注解进行解释说明的注解
@Target => 使用范围
@Retention => 描述注解生命周期
单元测试
JUnit测试 -> 白盒测试 如何完成成功(HOW) 能完成什么样(What)
- jar包准备 : junit + hamcrest-core
@Test
public void test(){
System.out.println("hello");
}
包装类
对基本数据类型进行包装 使得具备引用数据类型变量相关特征
Object->equals(Object obj) 基本数据类型不可用
ps: 成员变量默认值为null
内存解析
public static void main(Sting[] args){
int num = 520;
Integer obj = new Integer(520);
}
自动装箱与拆箱
java 5.0 新特性
int i = 10;
Integer n = i; // 自动装箱 valueof()
int i2 = n; //自动拆箱 xxxValue()
类型转换图
包装类缓存机制