语言设计以及开发过程中,将业务实现的思路:
过程式
面向过程
C
xx开门:
起立
向左转
走
10
步
向左转
走
2
步
伸手
用力
。。。
按部就班 过程式就是线型思维
对象式
面向对象
Java (
万事万物皆为对象
)
xx开门
xx
门
在宏观上把控事务的走向
我们时程序员,所以编写面向对象的代码的时候,本质上对象完成的功能还是按照面向过程去编写
的,面向对象和面向过程不是对立的。
1 如何构建一个对象?
类: 人类、动物类、植物类、分类、类别, 是一个抽象的概念,将实例、个体中的共性出去出来,归为
一类。
对象: 桌子、张三、电脑、登录、万事万物皆为对象
类和对象的关系
?
类时对于对象的抽象,抽取对象像的部分。 就是一个模板,由此可以产生
N
个对象。
new
对象时类的具象化表现形式,具体之后的产物。每个对象都是通过类产生的一个唯一的、独立
的个体。
先有对象?先有类?
构建: 先有对象 才有的类
实现:先有类才有对象
2 如何创建一个类以及如何创建对象
2.1 变量的分类
按照声明位置不同分为局部变量和成员变量:
成员变量:
声明在类中,方法外的变量
public class Demo{
int num;
public static void m(){}
}
生命周期: ?
成员变量无需初始化,因为会给一个默认值。
所有的整数 :
byte
、
short
、
int
、
long
给
0
所有小数:
double float
给
0.0
boolean
:
false
char : ' '
空格
引用类型:
null
局部变量:
声明在方法中或者时代码块中的变量
局部变量要想使用必须要保证先赋值
(
声明和初始化放在一起
)
局部变量的生命周期在当前声明之后都整个声明的代码块结束的位置结束。
public static void m(){
int n = 10; // 该位置开始声明
for (int i = 0;;){ //在这个位置声明
}//i在这个位置生命周期结束
System.out.println(i);
} // n在这个位置生命周期结束
2.2 创建类以及对象
创建类:
person
类
张三: 李四: 王五:
性别、年龄、身高、姓名。。。。。 外在的表现形式
-->
变量
(
成员变量
)
【位置】
吃饭、睡觉、打豆豆。。。
内在的功能
-->
方法(成员方法)
Tips
: 成员
->
对象
->
实例
表现形式就是非
static
修饰
package com.yjxxt.oop.classandinstance;
/***
创建一个person类:
* 成员变量: 抽取出的共性--> 外在的表现形式
* 成员方法: 抽取的共性 --> 内在的能力、功能
*
*/
public class Person {
/* 属性、字段、域 */
String name;
int age;
boolean gender; // true->男 false->女
/* 方法、功能 */
public void eat(){
System.out.println("正在吃饭");
}
public void sleep(){
System.out.println("正在睡觉");
}
}
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
p1.name = "王狗蛋"; // p1name修改了
String name = p1.name; // name = null
System.out.println(name);//name
}
}
Tips:
创建对象的模板:
类名 变量名 = new 类名();
自己创建的类就是创建了一个新的数据类型,这个新的类型时引用类型。
3 .1内存分析
以后但凡看见了
new
关键词,做三件事:
开空间
(
堆
)
初始化
(
成员变量
)
指向引用
(
将堆的地址赋值给变量存放
)
![](https://img-blog.csdnimg.cn/20210824151120314.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Zhc2FzZl9mYWY=,size_16,color_FFFFFF,t_70)
问题: 创建一个小孩对象。
名字、年龄
|
吃饭、哭
3.2 构造器
构造器的作用就是通过
new
关键词调用之后,产生当前类的实例的方法
修饰符 类名(){
}
public Children(){
}
3.2.1 要求
方法名称和类名一致
无返回值
无返回语句
每个类会默认存在一个空参数的构造器,当当前类中存在其他任意构造器时,系统默认增加的空构
造器就不存在了。
构造器允许方法重载
构造器之间的互相调用不能直接通过方法名进行。
3.3 this关键词
3.3.1 this()
专门用来调用构造器的。
必须保证在使用
this()
时,当前该代码在构造器的首行显示。
其他方法不能使用
this()
来调用构造器
3.3.2 this
当前对象,谁在执行,谁是当前对象。
不可省略:
出现了同名变量时 不可省略。区分同名变量的。
public Children(String name){
this.name = name;
}
可省略:
不存在同名变量时,默认存在
this.
public void cry(){
System.out.println(name+"哭吧哭吧不是罪!!!");
this.eat();
}public void eat(){
System.out.println("oooooooooooo");
}
内存分析:
![](https://img-blog.csdnimg.cn/20210824151923147.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Zhc2FzZl9mYWY=,size_16,color_FFFFFF,t_70)
3.4 static关键词
static:
静态的、共享的。
static int num;
double d;
public static void main(String[] args) {
System.out.println(num);
StaticTest t = new StaticTest();
System.out.println(t.d);
t.m();
}
public void m(){
System.out.println(num);
}
静态内容调用静态内容
本类中: 直接调用
其他类中:通过类名调用
StaticTest.num
静态内容调用非静态内容
创建对象
StaticTest t = new StaticTest();
System.out.println(t.d);
非静态调用静态
直接调用
非静态调用非静态
直接调用
Tips:
加载机制的时机问题:
一个类被加载,所有静态内容会被加载,就可以使用。
非静态内容也会被加载,但是非静态内容时隶属于对象的,如果要调用,必须确保对象存在。
类加载之后,无法确定一定存在对象。
为什么静态调用非静态需要创建的对象
?
为什么非静态调用静态无需创建对象?
![](https://img-blog.csdnimg.cn/20210824152527966.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Zhc2FzZl9mYWY=,size_16,color_FFFFFF,t_70)
3.5 面向对象的三大特性
3.5.1 继承
父类产生过程: 将多个子类中的共性抽取出来,形成父类,以提高代码的复用性。
1
、 如何继承
?
class F{
}
class S extends F{
}
2
、继承的问题
在
Java
中只支持单继承。所以呢复用性提升的有限。另外我们不太确定随着业务的发展之后,继承
关系是否还有必要,所以此时使用继承时需要格外谨慎。一旦出现
A
继承
B
,随着业务发展,发现
A
更加适合继承
C
,此时的调整办法为:
A->B->C
,但是需要格外注意,一般情况下我们要求继承链
的长度不要超过
3
3
、
super
关键词
super
和
this
的用法基本一致。
super
:父类对象的。
this
:当前对象的。
super();
调用父类的空构造器
在子类的构造器中,第一行默认情况下时
super()
;
。
super()
和
this()
不能同时显示的出现在构造器中
public class Sq{
/* 构造器 */
public Sq(){
this(5);
System.out.println("sq构造器");
}
public Sq(int length){
//super(); 默认会存在
System.out.println("sq带参构造器");
this.length = length;
}
}
public class Shape{
public Shape(){
System.out.println("Shape构造器");
}
}
子类想要创建对象,那么一定要存在父类。
Tips: 一个类在产生对象之前,需要先执行父类的构造器(默认情况下执行的是父类的空构造器)。
super.
不可省略 区分子类和父类中的同名变量或者是方法。
4
、重写
父类中的
方法
不满足子类的要求,此时子类需要重写。
如何判定一个方法是否时重写的方法:
在当前方法的上面 通过注解标注
@Override
如果不报错证明重写无误
重写一定要发生继承关系,且方法同名。
返回值
父类
>=
子类
参数列表相同
修饰符 子类
>=
父类
(
可见性
)
5
、
Object
类
所有类的父类,当一个类没有显示的指定父类时,那么它的父类默认时
Object
。超类、根基类、基类
.
hashCode() ; // 获取一个对象的hash值
getClass(); // 获取一个对象对应的Class对象
wait(); // 等待线程召唤
notify(); notifyAll(); // 唤醒线程
finalize(); // GC回收时 会自动调用
public boolean equals(Object obj){
return this==obj;
}
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;
}
String
中
equals
方法比较的是两个字符串的每个元素是否相同。
String
字符串底层就是字符数组。
作业
public class Student {
int id; String name;
boolean gender;
int score;
/*补齐构造器*/
/*equals 如果两个学生兑现的id、name、gender、score相同,同一个对象*/
}
6
、代码块
{
}
局部代码块:
声明的位置在方法内:
public static void main(String[] args) {
{
int num = 10;
System.out.println(num);
}
}
缩减
num的作用域,减少了内存消耗。
静态代码块:
被
static
修饰的代码块
,
类中、方法外
static{
System.out.println("我是静态代码块");
}
类被加载的时候,会自动执行,且只执行一次。
类加载的时机
:
主动加载
创建对象
new
调用当前类的静态内容
当前类时启动类
(main
方法
)
被动加载
(
不会导致类加载
)
final
修饰的静态内容如果在编译期间能够确定值,那么调用时不会导致类加载,反之如果编译期间
不能确定,则会导致类加载。
public class TestFinal {
public static final int num = 4;//(int)Math.random();
static{
System.out.println("我被执行了");
}
}
初始化块:
{
初始化块
}
定义在方法外、类中的代码块,每次创建当前类的实例时,都会被调用。
反编译之后:
public CodeBlock(){
System.out.println("初始化块");
System.out.println("空构造器");
}
7
、类加载顺序
类是否被加载了
?
静态代码块 (父类先于子类)
代码块(父类先于子类)
-->
代码块会在构造器中
构造器(父类先于子类)
3.5.2 封装
打包,将多个、多行代码打包到一起。安全。
学习封装就是在学习修饰符。
public
公开的 公共的
默认的
修饰符不写
private
私有的
1
、 属性的封装
package com.yjxxt.oop.box;
public class Student {
int id;
String name;
private int age;
public Student(){
}
public Student(int id,String name,int age){
this.id = id;
this.age = age;
this.name = name;
}
public String toString(){
return this.id+","+this.name+","+this.age;
}
public void setAge(int age){
if (age>=0&&age<150) {
this.age = age;
}
}
public int getAge(){
return this.age;
}
}
属性封装、让当前类更加安全,避免一些错误的赋值或者时获取操作。
2
、方法封装:
3
、构造器封装:
1
: 工具类中包含的方法属性基本上都是
static
的,此时无需创建的对象,所以将构造器私有。
private StringUtils(){
}
2
:单例模式
饿汉式
:
天然线程安全 缺点 不能延迟加载
/**
* 单例设计模式:
* 饿汉式
*
*/
public class Single {
private static Single single = new Single();
private Single(){
}
public static Single getInstance(){
return single;
}
}
懒汉式: * n能够做到延迟加载,线程不安全
public class LazySingle {
private static LazySingle single ;
private LazySingle(){}
public static LazySingle getInstance(){
if (single==null){
single = new LazySingle();
}
return single;
}
}
包和导包
包:
在当前类的首行指定当前类所在的包:
统一小写
package com.域名.项目名.模块;
包的目的是为了唯一去标识类,一个类的唯一标识: 全限定名
=
包名
.
类名
;
导包:
Tips: java.lang
包下的类不需要导入,可以直接使用。
使用某个类,需要确定这个类在哪里。
import
语句在当前类的第二行
import java.util.Scanner;
import java.util.*;
jdk1.5
之后支持静态导入
import static java.lang.Math.*;
System.out.println(PI);
System.out.println(pow(10,3));
如果当前类中需要引入同名类,此时可以将一个类通过
import
方式引入 另外一个通过全限定名引入
com.yjxxt.oop.ext.Student stu1 = new com.yjxxt.oop.ext.Student();
3.5.3 多态
在
Java
中 ,某个变量具备多种形态
package com.yjxxt.oop.dt;
public class Test {
public static void main(String[] args) {
Person p = new Student(); //父类变量指向了子类对象
p.eat(); // 编译看左边、运行看右边
}
}
class Person{
private String name;
public Person(){}
public void eat(){
System.out.println("person eat");
}
public void setName(String name) {
this.name = name;
}
public String getName(){
return this.name;
}
}
class Student extends Person{
public Student(){
}
@Override
public void eat(){
System.out.println("吃大餐");
}
}
在编译期间,
p
变量是
person
类型,但是运行时,实际时
student
。此时我们称之为发生了多态。 多
态只针对方法不针对属性。
多态的产生条件
必须有继承关系
必须要保证子类重写了父类中的某些方法
父类变量指向了子类对象
调用从写方法时,才能确报构成多态
复习面向对象
类和对象的关系
类中存在的内容
属性
修饰符
[static] [final]
数据类型 变量名
;
构造器
修饰符 类名
([
参数
]);
this();
第一行
方法
修饰符
[static] [void|
数据类型
]
方法名
(
参数
)
static
static
修饰的从属于类 类存在他就存在 所以比对象块
static{}
类加载就会被默认调用一次
面向对象三大特性
继承:
extends
重写
封装:
4
个关键词
多态:
Tips:
为什么要定义父类、父类中的方法有什么用
?
3.5.4
抽象类
抽象的类,类: 比较抽象的内容。
抽象类的声明
// 通过abstract修饰的类称之为抽象类
abstract class A{
}
抽象类的内容
abstract class Drink{
int num;
public Drink(){
}
public abstract void m();
}
抽象类中可以声明变量
可以声明构造器
可以声明普通方法和抽象方法
通过
abstract
修饰的,只有方法声明二没有方法体。
抽象类的作用就是为了让子类继承
一个类如果继承了抽象类,必须要实现抽象类中的所有抽象方法
抽象了时可以发生继承关系的,子类继承了抽象类之后,需要将所有的
(
继承链
)
的抽象方法全部实
现
package com.yjxxt.oop.dt;
public class Test02 {
public static void main(String[] args) {
}
}
abstract class Drink extends Person{
int num;
public Drink(){
}
public abstract void m();
//public abstract void f();
}
class Caff extends Drink{
@Override
public void m(){
}
}
模板方法
Drink
喝茶 烧水 倒入 醒 干了
喝咖啡 烧水 倒入 搅拌 干了
3.5.5 final
fianl
可以修饰变量、修饰类、修饰方法。
final
修饰的变量
常量,运行期间其值不能发生改变
final int num = 10; //
num = 5 ; error 12
final
修饰类
final
修饰的类不能被继承、防止继承。太监类
final
修饰的方法
被
final
修饰的方法不能被重写
abstract class Drink{
public final void guluguluWater(){
System.out.println("烧水");
}
public final void hua(){
System.out.println("倒入");
}
public abstract void dengDai();
public final void ganLe(){
System.out.println("干了");
}
public final void flow(){
this.guluguluWater();
this.hua();
this.dengDai();
this.ganLe();
}
}
class Caff extends Drink{
/* @Override
public void guluguluWater(){
}*/
public void dengDai(){
System.out.println("搅拌");
}
}
class Tea extends Drink{
public void dengDai(){
System.out.println("洗~~~");
}
3.5.6
接口
标准时一套准则,概念。不是具体的实现。接口就是一个标准。接口描述的是一种
hava
-
a
的关系。
存在以下实例对象:
飞机、导弹、小鸟、超人
接口声明
[修饰符] interface 接口名{ }
接口中定义的内容
接口中定义的属性都是默认通过
public static final
修饰的,所以成员变量不写修饰符,默认
也是这些关键词修饰的。接口中定义的成员变量必须要初始化。
接口中不能包含构造器
接口中定义的方法都是
public abstract
修饰的。都是抽象方法。
jdk1.8
之后可以允许在接口中定义默认方法
default void m(){
}
类和接口的关系
时实现的关系,
Java
类只能继承一个类,但是可以实现多个接口
class SuperMan extends Person implements Fly, Serializable,Comparable {
@Override
public void fly(){ System.out.printl
System.out.println("双脚一登。。。。。");
}
@Override
public int compareTo(Object o) {
return 0;
}
}
接口可以继承其他接口,并且可以继承多个接口,实现类实现接口之后需要实现该接口所有的抽象
方法
(
包含接口的父接口
)
public interface Fly extends Serializable,Comparable{ }
接口是可以允许完成多态的。
3.5.7 内部类
内部类分为:局部内部类、普通内部类、静态内部类
[
重点
]
、匿名内部类。
局部内部类
定义在方法内的类,只能通过
默认修饰符
+
abstract
或者时
final
修饰。指定定义对象的方法或者时成员变量。
public static void m(){
final class A{
public void f(){
}
}
new A().f();
}
普通内部类
定义在类里面的类
package com.yjxxt.oop.inner;
public class Test02 {
public static void main(String[] args) {
new Outer01().f();
new Outer01().new Inner01().m();
}
}
class Outer01{
int n ;
public void f(){
System.out.println(n);
new Inner01().m();
}
private class Inner01{
int num = 10;
public void m(){
System.out.println("inner01-m");
//Outer01.this.f(); 默认内部类会持有一个外部类对象的引用 }
}
}
}
内部类会持有一个外部类对象的引用
外部类
.this
其他类访问内部类时
new 外部类().new 内部类();
静态内部类
作为外部类的一个静态成员去理解。
package com.yjxxt.oop.inner;
public class Test03 {
public static void main(String[] args) {
new Outer02().m();
new Outer02.Inner02();
}
}
class Outer02{
int m;
public void m(){
new Inner02().f();
}
static class Inner02{
int n;
public void f(){
System.out.println("inner02 f");
new Outer02().m();
}
}
}
匿名内部类
Test04.filter(new Filter() {
@Override
public void filter(Stu[] stus) {
for (int i = 0;i<stus.length;i++){
Stu stu = stus[i];
if (stu.getScore()>10&&stu.getAge()>25){
System.out.println(stu);
}
}
}
},stus);
单例模式
package com.yjxxt.oop.inner;
/**
* 单例: 通过该类只能创建一个对象
*
*/
public class Single {
//static Single single = new Single();
static class Singleton{
static Single single = new Single();
}
private Single(){
}
public static Single getInstance(){
return Singleton.single;
}
public static void aVoid(){
}
}
静态内部类完成的单例模式线程安全且能够做到延迟加载
1
:理解静态内部类
就是一个静态属性、静态
2
:静态内部类本质上还是一个类 所以 导致类加载的实际也可以使用在它身上
3.5.8 可变参数
jdk1.5 之后支持可变参数
jdk1.5 之后支持可变参数
m(1,2,3,4,5,6,7,8,9,0,1,1,2,3,4,6,7);
public static void m(int ... n){
System.out.println("执行了");
}
public class Test07
{
public static void main(String[] args)
{
byte b = 10;
int n = 20;
m(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 1, 2, 3, 4, 6, 7 });
}
public static void m(int[] n)
{
{ System.out.println("执行了");
}
}
可变参数一定时在参数列表的末尾,并且有且只能有一个。
public static void m(String oper,int ... n){}