java从入门到精通OOP

文章目录

    • 1 面向对象1
      • 1.1 面向对象
        • 1.1.1 概念
        • 1.1.2 三大特征
      • 1.2 类和对象
        • 1.2.1 类
        • 1.2.2 对象
        • 1.2.3 类和对象的关系
      • 1.3 类和对象的创建和使用
        • 1.3.1 练习1:类的创建使用
        • 1.3.2 对象在内存中的存储
        • 1.3.3 单一对象内存图
        • 1.3.4 练习2:创建多个类
        • 1.3.5 多对象内存图
      • 1.4 封装
        • 1.4.1 概述
        • 1.4.2 private关键字
        • 1.4.3 练习1:封装学生
      • 1.5 拓展
        • 1.5.1 创建Teacher类,并创建Teacher对象测试
        • 1.5.2 编写汽车类并画内存图
        • 1.5.3 创建对象的流程
        • 1.5.4 匿名对象
    • 2 面向对象2
      • 2.1 构造方法
        • 2.1.1 概念
        • 2.1.2 形式
        • 2.1.3 练习1:构造方法创建对象
        • 2.1.4 练习2:构造方法赋值
      • 2.2 构造代码块和局部代码块
        • 2.2.1 构造代码块
        • 2.2.2 局部代码块
        • 2.2.3 练习1:代码块加载顺序
      • 2.3 this关键字
        • 2.3.1 概念
        • 2.3.2 形式
        • 2.3.3 练习1:当变量名相同时
        • 2.3.4 练习2:构造方法间的调用
      • 2.4 继承
        • 2.4.1 概念
        • 2.4.2 特点
        • 2.4.3 入门案例
      • 2.5 super关键字
      • 2.6 方法的重写
      • 2.7 继承中的用法
        • 2.7.1 成员变量的使用
        • 2.7.2 成员方法的使用
        • 2.7.3 构造方法的使用
      • 2.8 拓展
        • 2.8.1 this和super的区别
        • 2.8.2 重写与重载的区别(Overload和Override的区别)
        • 2.8.3 继承的内存结构
    • 3 面向对象3
      • 3.1 static
        • 3.1.1 概念
        • 3.1.2 特点
        • 3.1.3 练习1:入门案例
        • 3.1.4 静态方法内存图
        • 3.1.5 练习2:静态调用关系
      • 3.2 静态代码块、构造代码块、局部代码块
        • 3.2.1 静态代码块
        • 3.2.2 概述
        • 3.2.3 测试
      • 3.3 final
        • 3.3.1 概念
        • 3.3.2 特点
        • 3.3.3 入门案例
      • 3.4 多态
        • 3.4.1 概念
        • 3.4.2 特点
        • 3.4.3 入门案例
      • 3.5 多态的好处
      • 3.6 多态的使用
        • 3.6.1 特点
        • 3.6.2 测试
      • 3.7 拓展
        • 3.7.1 静态代码块,构造代码块,局部代码块
        • 3.7.2 静态变量和实例变量的区别
        • 3.7.3 向上转型和向下转型
        • 3.7.4 设计多态的程序
    • 4 面向对象4
      • 4.1 异常
        • 4.1.1 概述
        • 4.1.2 异常的继承结构
        • 4.1.3 异常处理
        • 4.1.4 测试
        • 4.1.5 自定义异常
      • 4.2 访问控制符
      • 4.3 抽象类
        • 4.3.1 概念
        • 4.3.2 特点
        • 4.3.3 入门案例
      • 4.4 抽象类的用法
        • 4.4.1 构造函数
        • 4.4.2 抽象类的成员变量
        • 4.4.3 抽象类的成员方法
      • 4.5 分析老师示例
    • 5 面向对象5
      • 5.1 接口
        • 5.1.1 概念
        • 5.1.2 特点
        • 5.1.3 入门案例
      • 5.2 接口的用法
        • 5.2.1 构造方法
        • 5.2.2 成员变量
        • 5.2.3 接口的成员方法
      • 5.3 接口的复杂用法
      • 5.4 总结
      • 5.5 设计模式
        • 5.5.1 单例设计模式概念
        • 5.5.2 源码剖析
        • 5.5.3 饿汉式
        • 5.5.4 懒汉式
      • 5.6 拓展
        • 5.6.1 abstract注意事项
        • 5.6.2 接口和抽象类的区别
        • 5.6.3 设计学员示例
        • 5.6.4 了解软件设计的开闭原则OCP

1 面向对象1

1.1 面向对象

1.1.1 概念

所谓的面向对象是一种编程思想,通过这种思想可以把生活中的复杂事情变得简单化,从原来的执行者变成了指挥者,面向对象是基于面向过程而言的。
我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)

 面向过程强调的是过程,例如:
1、打开冰箱 2、把大象放进去 3、关上冰箱

 面向对象强调结果,例如:
1、 饿了,去平台点餐,这个动作就是面向对象。你没有去市场买菜洗菜做饭。。。只要有app就可以了。
2、 衣服脏了,直接甩给女票去处理等着穿干净的就可以了。你没有关注中间的过程。。只要找好对象就可以了。
3、面试官问什么是面向对象?你答万物皆对象!!不建议因为你还没到这个深度,最好举例。就像是,你说空即是色色即是空—信你个鬼。

1.1.2 三大特征

1、 封装性,把相关的数据封装成一个“类”组件
2、 继承性,是子类自动共享父类属性和方法,这是类之间的一种关系
3、 多态,增强软件的灵活性和重用性

1.2 类和对象

1.2.1 类

1、 Java语言最基本单位就是类,类似于类型。
2、 类是一类事物的抽象。
3、 可以理解为模板或者设计图纸。

1.2.2 对象

每个对象具有三个特点:对象的状态,对象的行为和对象的标识。
1、 对象的状态用来描述对象的基本特征。
2、 对象的行为用来描述对象的功能。
3、 对象的标识是指对象在内存中都有一个唯一的地址用来和其他对象区分开来。
4、 类是一类事物的抽象,对象是具体的实现。

1.2.3 类和对象的关系

1、 计算机语言是用来描述现实世界事物的。属性+行为
2、 那怎么通过java语言描述呢?通过类来描述事物,把事物的属性当做成员变量,把行为当做成员方法。
分析手机事物:
属性:颜色,尺寸,品牌,价格。。。
方法:打电话,发短信,听音乐。。。。
类:手机类,抽取相同的属性和行为
对象:可以按照模板生产很多个手机,比如1号手机对象,包含特有的成员变量和成员方法
java从入门到精通OOP_第1张图片

1.3 类和对象的创建和使用

1.3.1 练习1:类的创建使用

通过class关键字创建类,通过new关键字创建对象。

package day000000;

public class Test1 {
	public static void main(String[] args) {
		//p是引用对象,持有了对于Person对象的地址值的引用
		//此时的p,含有属性,但都是默认值
		Person p = new Person();
		//设置属性值
		p.name="lisi";
		p.age=20;
        //调用方法
		p.eat();
	        p.sleep();
		
	} 
}

class Person{
	//属性--成员变量
	String name;
	int age;
	
	//行为--方法
	void eat(){
		System.out.println("吃饭饭");
	}
	
	void sleep(){
		System.out.println("睡觉觉");
	}
}

1.3.2 对象在内存中的存储

Java把内存分成5大区域,我们重点关注栈和堆。
java从入门到精通OOP_第2张图片

1、 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
2、 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
3、 每个堆内存的元素都有地址值
4、 对象中的属性都是有默认值的

1.3.3 单一对象内存图

Person p = new Person();

java从入门到精通OOP_第3张图片

1、 在栈内存中,创建一个引用变量p,持有对象的地址值
2、 在堆内存中,创建Person对象,并且开辟变量的空间,完成初始化
3、 给堆内存中的元素,分配一个唯一标志,地址值。交给p去保存。
4、 p.name=”lisi”;p.age=20;就去堆内存中找唯一的地址值,找到Person对象,并对其属性进行修改赋值。
5、 p.eat();就去堆内存中找唯一的地址值,找到Person对象,执行Person对象的方法。

1.3.4 练习2:创建多个类

package day000000;

public class Test1 {
	public static void main(String[] args) {
		//p是引用对象,持有了对于Person对象的地址值的引用
		//此时的p,含有属性,但都是默认值
		Person p = new Person();
		//设置属性值
		p.name="lisi";
		p.age=20;
		//创建p2
		Person p2=new Person();
		p2.name="zhangsan";
		p2.age=10;
		
	} 
}

class Person{
	//属性--成员变量
	String name;
	int age;
	
	//行为--方法
	void eat(){
		System.out.println("吃饭饭");
	}
	
	void sleep(){
		System.out.println("睡觉觉");
	}
}

1.3.5 多对象内存图

java从入门到精通OOP_第4张图片

1、 变量p和变量p1不是一片空间,p1需要开辟新的空间
2、 Person p1=new Person,这时只要有new,就会新开辟空间在堆内存中存入对象。

1.4 封装

1.4.1 概述

封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式。
好处:
1、 提高安全性
2、 提高重用性
案例:
1、 类
2、 方法

1.4.2 private关键字

是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法。

1.4.3 练习1:封装学生

先用不同的变量名,不要出现this

package day006;

public class Student {
//String name;
	//把属性隐藏起来
	private String name;
	//提供公共的访问方法
	//设置公共的赋值方法
	public void setName(String n){
		name=n;
	}
	
	//设置公共的取值方法
	public String getName(){
		return name;
	}	
	int age;
}

class StDemo{
	public static void main(String[] args) {
		Student s = new Student();
		//不能访问私有的
		//s.name="zhangsan";
		//System.out.println(s.name);s
		//利用setXxx()给属性赋值
		s.setName("zhangsan");
		//利用getXxx()给属性取值
		System.out.println(s.getName());
	}
}

1.5 拓展

1.5.1 创建Teacher类,并创建Teacher对象测试

老师事物:设置特性和功能
特征:姓名、年龄、住址
功能:讲课

测试:
创建Teacher对象
调用老师的属性和功能
修改老师的属性

1.5.2 编写汽车类并画内存图

属性:颜色,型号,品牌,价格
行为:开,飞。。。
汽车对象的创建和使用

1.5.3 创建对象的流程

Person p = new Person();//短短这行代码发生了很多事情
  1. 把Person.class文件加载进内存
  2. 在栈内存中,开辟空间,存放变量p
  3. 在堆内存中,开辟空间,存放Person对象
  4. 对成员变量进行默认的初始化
  5. 对成员变量进行显示初始化
  6. 执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
  7. 堆内存完成
  8. 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值

1.5.4 匿名对象

没有名字的对象,是对象的简化表示形式。
使用场景:
1、 当被调用的对象只调用一次时(多次会创建多个对象浪费内存)

Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字,匿名对象就是有对象但是没有名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法

2 面向对象2

2.1 构造方法

2.1.1 概念

构造方法是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化。当类实例化一个对象时会自动调用构造方法。
构造方法和其他方法一样也可以重载。

2.1.2 形式

可以无参也可以有参

修饰符  类名(【参数】){
	代码……
}

2.1.3 练习1:构造方法创建对象

创建对象时的两种方

package day006;

public class Test2_构造方法 {

	String name;
//当存在一个含参的构造方法时,无参构造将不再自动生成...	
//public Test2_构造方法(){}

		//含参构造
	public Test2_构造方法(String n){
		name=n;
	}
	void eat(){
		System.out.println("Test2_构造方法.eat()");
	}
}

class tt{
	public static void main(String[] args) {
//注释掉无参的构造也可以运行,说明系统会自动提供一个无参的构造方法
		Test2_构造方法 t2 = new Test2_构造方法();
		t2.eat();		

//t是引用变量,引用的是对象的地址值。
		//根据地址值找到对象,并获取对象的数据
		Test2_构造方法 t = new Test2_构造方法("张三");
		System.out.println(t.name);
	}
}

2.1.4 练习2:构造方法赋值

package day006;

public class Test3_成员变量赋值 {
	
	String name;
	int age;
	
	//赋值方式1:通过含参构造方法赋值
	public Test3_成员变量赋值(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	//赋值方式2:通过setXxx()方法赋值
	public void setName(String name){
		this.name=name;
	}
	public void setAge(int age){
		this.age=age;
	}
	
}



class Test3Demo{
	public static void main(String[] args) {
		
		//赋值方式1:通过无参构造方法赋值
		Test3_成员变量赋值 t1= new Test3_成员变量赋值();
		System.out.println(t1.name);
		System.out.println(t1.age);
		
		//赋值方式1.1:通过含参构造方法赋值
		Test3_成员变量赋值 t2= new Test3_成员变量赋值("zhangsan",30);
		System.out.println(t2.name);
		System.out.println(t2.age);
		
		//赋值方式2:通过setXxx()方法赋值
		Test3_成员变量赋值 t3= new Test3_成员变量赋值();
		t3.setName("rose");
		t3.setAge(25);
		System.out.println(t3.name);
		System.out.println(t3.age);
	}
}

2.2 构造代码块和局部代码块

2.2.1 构造代码块

1、 在类的内部,方法外部,的代码块。
2、 通常用于抽取构造方法中的共性代码。
3、 每次调用构造方法前都会调用构造代码块
4、 优先于构造方法加载

class c{
	String country;
	{
		country="中国";
	}
	public c() {
		System.out.println("1号选手,来自"+country);
	}
	public c(int a) {
		System.out.println("2号选手,也来自"+country);
	}
}

2.2.2 局部代码块

1、 在方法里面的代码块
2、 通常用于控制变量的作用范围,出了括号就失效
3、 变量的范围越小越好,成员变量会有线程安全问题
4、 总结:执行顺序:
构造代码块是最优先的,局部代码块顺序执行

2.2.3 练习1:代码块加载顺序

package day99999;
public class TT {
	public static void main(String[] args) {
		Student s = new Student();
		s.init();
	}
}

class Student{
	{
		System.out.println("构造代码块1");
	}
	
	public void init(){
		{
			System.out.println("局部代码块");
		}
	}
	
	{
		System.out.println("构造代码块2");
	}
}

2.3 this关键字

2.3.1 概念

this代表本类对象的一个引用对象。
构造函数中使用时,必须放在第一行。

2.3.2 形式

name=name;
age=age;

其实是想把Student类的局部变量name的值赋值给成员变量,相当于你想操作是这样的:
//Student.name=name;
但是你不能直接写类名,这时候就用代表本类的对象this来完成。代码变成了:
this.name=name;

2.3.3 练习1:当变量名相同时

当局部变量和成员变量同名时,用于区分。
如果附近有同名变量,会遵从变量的就近原则,那么怎么调用成员变量呢?

package day99999;
public class T {
	public static void main(String[] args) {
		Animal a = new Animal();
		a.run("大黄");
		System.out.println(a.name);
	}
		
}

class Animal{
	String name;
	/*
	//当局部变量的名字和成员变量不一样时简单,拿着局部变量的值直接给成员变量赋值就行了
	public void run(String n){
		name=n;
	}*/
	//问题来了,当局部变量和成员变量同名时呢??
	public void run(String name){
//name=name;//变量的就近使用原则,这样用的都是最近的也就是一直在用局部变量的
		this.name=name;//this调用成员变量
	}
}

2.3.4 练习2:构造方法间的调用

package day99999;
public class T {
	public static void main(String[] args) {
		Animal a = new Animal();
//		Animal a2 = new Animal("旺财");
		
	}
}

class Animal{
	public Animal(){
		this("来福");//调用本类中的含参构造
		System.out.println(name);
	}
	
	public Animal(String name){
		System.out.println(name);
	}
}

2.4 继承

2.4.1 概念

继承是面向对象最显著的一个特性。
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类/超类/基类。
这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
提高复用性:只要继承父类,就能有一样的功能

class A extends c{  //原来的eat()拿走了   }
class B extends c{  //原来的eat()拿走了  }
class c{
	public void eat(){
		syso("eat");
	}
}

2.4.2 特点

1、 使用extends关键字
2、 相当于子类把父类的功能复制了一份
3、 java只支持单继承
4、 继承具有传递性(爷爷,儿子,孙子的关系)
5、 不能继承父类的私有成员
6、 继承多用于功能的修改,子类可以拥有父类的功能的同时,进行功能拓展
7、 像是is a 的关系

2.4.3 入门案例

package day99999;
public class TTT {
	public static void main(String[] args) {
		Zi zi = new Zi();
		zi.speak();
		System.out.println(zi.skin);
		System.out.println(zi.addr);
	}
}

class Fu{
	String skin="黄种人";
	String addr="大成都";
	
	public void speak(){
		System.out.println("Fu...speak()");
	}
}

//通过extends和父类发生继承关系
//所有父类的功能,子类都可以继承过来,注意不能是private的
class Zi extends Fu{
	//什么都不写,能不能把父亲的内容复制一份出来
}

2.5 super关键字

1、 通过super关键字可以使用父类的内容
2、 super代表父类的一个引用对象
3、 如果用在构造方法里时,必须出现在第一行

2.6 方法的重写

1、 继承后,子类就拥有了父类的功能
2、 那么在子类中,可以添加子类特有的功能也可以修改父类的原有功能
3、 子类中方法签名与父类完全一样(包括方法的返回值,方法名和参数列表,完全一致)时,会发生覆盖/复写操作,相当于修改功能
注意:
1、父类中的私有方法不能被重写
2、子类重写父类方法时,修饰符要大于等于父类修饰符的权限

2.7 继承中的用法

2.7.1 成员变量的使用

局部的,成员的,父类的。

package day000;
public class Test2_LeiVariable {	
	public static void main(String[] args) {
		Sub2 s= new Sub2();
		s.show();
	}
}

class Fu2{
	int num=20;
}

class Sub2 extends Fu2{
	int num;
	public void show(){
		int num=9;
		System.out.println(num);//变量的就近原则
	System.out.println(this.num);//调用本类的成员变量,相当于Sub2.num
		System.out.println(super.num);//调用父类的成员变量
	}
}

2.7.2 成员方法的使用

继承方法,特有方法,重写方法

package day000;
public class Test3_LeiMethod {
	public static void main(String[] args) {
		Sub3 s=new Sub3();
		s.testShow();//调用普通方法,
s.eat();//调用重写方法,子类已经重写了父类的方法,从此再用,就是儿子的实现方式
	}
}
class Fu3{

	public void show(){
		System.out.println("Fu...show()");
	}
	
	public void eat(){
		System.out.println("爸爸吃肉");
	}
}
class Sub3 extends Fu3{
	//普通方法
	public void testShow(){
		super.show();//调用父类的eat()
	}
	
	//重写方法
	//方法签名完全一致的情况就是发生了重写
	public void eat(){
		System.out.println("儿子吃肉");
	}
	
}

2.7.3 构造方法的使用

1、 子类创建对象时,默认会去访问父类的无参构造方法
2、 在构造方法的第一行,都有一条默认的语句:super();
3、 父类没有无参构造时,可以用super调用父类的其他构造

package day000;
public class Test4_LeiConstruct {
	public static void main(String[] args) {
Sub4 s = new Sub4();//创建子类对象,在调用子类无参构造前,会先去调用父类的无参构造
	}
}

class Fu4{
	public Fu4(){
		System.out.println("Fu4.Fu4()");
	}
	
	public Fu4(String name){
		System.out.println("Fu.."+name);
	}
}

class Sub4 extends Fu4{
	public Sub4(){
//		super();//默认就存在的,而且在第一行
		super("zhangsan");//调用父类中含参的构造方法
		System.out.println("Sub4.Sub4()");
	}
	
	public Sub4(String name){
		this();//调用本类的无参构造
		System.out.println("Sub.."+name);
	}
}

2.8 拓展

2.8.1 this和super的区别

1、 this代表本类对象的引用,super代表父类对象的引用。
2、 this用于区分局部变量和成员变量
3、 super用于区分本类变量和父类变量
4、 this.成员变量 this.成员方法() this(【参数】)代表调用本类内容
5、 super.成员变量 super.成员方法() super(【参数】),代表调用父类内容
6、 this和super不可以同时出现在同一个构造方法里,他们两个只要出现都得放在第一行,同时出现的话,到底第一行放谁呢。。

2.8.2 重写与重载的区别(Overload和Override的区别)

1、重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
2、重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
3、重写是父类与子类之间多态性的一种表现
4、重载是一类中多态性的一种表现

2.8.3 继承的内存结构

java从入门到精通OOP_第5张图片

3 面向对象3

3.1 static

3.1.1 概念

1、 是java中的一个关键字
2、 用于修饰成员(成员变量和成员方法)

3.1.2 特点

1、 可以修饰成员变量,成员方法
2、 随着类的加载而加载,优先于对象加载
3、 只加载一次,就会一直存在,不再开辟新空间
4、 全局唯一,全局共享
5、 可以直接被类名调用
6、 静态只能调用静态,非静态可以随意调用
7、 static不能和this或者super共用,因为有static时可能还没有对象

3.1.3 练习1:入门案例

package cc;
public class aa {
	public static void main(String[] args) {
		//特点2,优先于对象加载,有没有对象都有static
		int i = Student.age;
		System.out.println(i);
		
		//特点3,只加载一次,就会一直存在,不再开辟新空间 
		//创建对象
		Student s = new Student();
		Student s1 = new Student();
		//调用方法
		System.out.println(s.name);
		System.out.println(s.age);
		s.speak();
		s.eat();
		
	}
}
class Student{
	String name="张三";
	static int age=20;
	
	public void eat(){
		System.out.println("eat..");
	}
	
	public static void speak(){
		System.out.println("speak...");
	}
}

3.1.4 静态方法内存图

java从入门到精通OOP_第6张图片

3.1.5 练习2:静态调用关系

静态只能调用静态(变量或者方法),非静态可以访问所有的不管是不是静态

package cc;
public class O {
	public static void main(String[] args) {
		Teacher t = new Teacher();
		t.speak();
	}
}

class Teacher{
	static int age=30;
	String name="王康";
	
	//非静态测试
	public void speak(){
		System.out.println(age);//非静态能调用静态变量
		System.out.println(name);//非静态能调用非静态变量
		qiao();//非静态能调用静态方法
	}
	//静态测试
	public static void qiao(){
		System.out.println(age);//静态能调用静态
//		System.out.println(name);//静态不能调用非静态变量,只能调用静态变量
//		speak();//静态不能调用非静态方法,只能调用静态方法
	}
	
}

3.2 静态代码块、构造代码块、局部代码块

3.2.1 静态代码块

随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
static{…}

3.2.2 概述

1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
2、 构造代码块:在调用构造方法前会自动调用,每次创建对象都会被调用
3、 局部代码块:方法里的代码块,方法被调用时才会执行
4、 静态代码块:static{ },位置:在类里方法外
5、 TODO创建测试类,类中写好静态代码块,构造代码块,构造方法,普通方法里嵌套局部代码块。测试他们的执行顺序。
6、 静态 - 构造代码块 - 构造方法 - 局部

3.2.3 测试

package cn.tedu.staticdemo;

public class Test4 {
	public static void main(String[] args) {
		Car c = new Car();c.show();
		Car c2 = new Car();
	}
}
class Car{
	//静态代码块
	//1,在类第一次加载时就加载到内存中并一直驻存,
	//并全局共享,直到类消失静态资源才消失
	//2,并且静态资源只被加载一次
		static {
			System.out.println(1);
		}
		
		//构造代码块
		{
			System.out.println(2);
		}
		
		//	构造方法
		public Car() {
			System.out.println(3);
		}
		
		public void show() {
//		局部代码块
			{
				System.out.println(6);
			}
			System.out.println(4);
			System.out.println(5);
		}
}

3.3 final

3.3.1 概念

1、 是java提供的一个关键字
2、 final是最终的意思
3、 final可以修饰类,方法,成员变量
初衷是因为:java出现了继承后,子类可以更改父类的功能,当父类功能不许子类改变时可以利用final关键字修饰父类。

3.3.2 特点

1、 被final修饰的类,不能被继承
2、 被final修饰的方法,不能被重写
3、 被final修饰的变量是个常量,值不能被更改
4、 常量的定义形式: final 数据类型 常量名 = 值

3.3.3 入门案例

package cc;
public class P {
	public static void main(String[] args) {
		Zi d = new Zi();
		d.speak();
		System.out.println(d.name);
		d.test();
	}
}
class Fu{
//final lass Fu{//1,被final的类,不能被继承
	final String name="欢欢";
	public final void speak(){
		System.out.println("Fu..speak()");
	}
}
class Zi extends Fu{
	/*
	 //2,被final的方法,不能被重写
	 * public void speak(){
		System.out.println("Fu..speak()");
	}*/
	
	public void test(){
//		super.name="大黄";//3,被final的变量,不能重新被赋值
		System.out.println(super.name);
	}
}

3.4 多态

3.4.1 概念

多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。
主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
好处是可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
例如:水,在不同时刻可以有多种形态,包括水蒸气,冰,水。
Java怎么体现多态呢?狗有两种形态:狗和小动物

class Animal
class Dog extends Animal
Dog d = new Dog();//狗是狗
Animal  a=new Dog();//狗是小动物,创建了狗的对象,赋值给动物对象,这就是多态

3.4.2 特点

1、 多态的前提是继承
2、 要有方法的重写
3、 父类引用指向子类对象,如:Animal a = new Dog(); – 小到大,向上转型
4、 多态中,编译看左边,运行看右边

3.4.3 入门案例

package cc;

public class p {
	public static void main(String[] args) {
		/*Animal  a = new Animal();
		a.eat();
		
		Dog d = new Dog();
		d.kanjia();
		d.eat();*/
		
//父类引用指向子类对象--把右面的小的,给了左面大的。相当于从小到大的过程,向上造型。
		Animal an = new Dog();
		an.eat();//只可以用父类的功能,这就统一了调用的标准
		//狗吃肉,由于eat()发生了重写,所以父类方法被覆盖掉了
	}
}
class Animal{
	public void eat(){
		System.out.println("大小通吃");
	}
}
class Dog extends Animal{
	public void kanjia(){
		System.out.println("狗可以看家");
	}
	
	public void eat(){
		System.out.println("狗吃肉");
	}
}

3.5 多态的好处

1、 多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法。
2、 提高了程序的扩展性和可维护性

public class Q {
	public static void main(String[] args) {
		//多态--父类引用指向子类对象
		Dog a2=new Dog();
		Cat a2 = new Cat();
		Animal2 a2 = new Dog();
		eat(a2);//传入的参数满足条件就可以,运行右面的功能
	}
	
//封装共性方法,不关心具体类型,只要传入的参数是子类就可以
	public static void eat(Animal2 a){
		a.eat();
	}
}

3.6 多态的使用

3.6.1 特点

1、成员变量:使用的是父类的
2、成员方法:由于存在重写现象所以使用的是子类的
3、静态成员:随着对象而存在,谁调用的就返回谁的

3.6.2 测试

package cc;
public class K {
	public static void main(String[] args) {
		Fu2 f = new Zi2();//多态,只能用父类的。。。
		//多态的成员变量,就是父类的
		System.out.println(f.num);//10
		
		//成员方法,因为存在重写,所以是子类的
		f.study();//Zi..study()
		
		//静态成员,谁调用就是谁的
		System.out.println(f.count);//10
		f.sleep();//Fu..sleep()
	}
}

class Fu2{
	int num=10;
	static int count=10;
	public void study(){
		System.out.println("Fu..study()");
	}
	
	public static void sleep(){
		System.out.println("Fu..sleep()");
	}
}

class Zi2 extends Fu2{
	int num=20;
	static int count=20;
	public void study(){
		System.out.println("Zi..study()");
	}
	
	public static void sleep(){
		System.out.println("Zi..sleep()");
	}
}

3.7 拓展

3.7.1 静态代码块,构造代码块,局部代码块

!!!执行顺序:静态代码块—构造代码块—构造函数
1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
2、 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用
3、 局部代码块:方法里的代码块

package cc;

public class haha {

	public static void main(String[] args) {
		//必须创建对象,不然静态代码块咋随着类的加载而加载。。
		Block m =  new Block();//静态1  静态2  构造1  构造2  局部1
		System.out.println();
		Block m2 =  new Block();//构造1  构造2  局部1,说明静态代码只被执行一次就是在类第一次初始化时
	}
}
class Block{
	{
		System.out.println("构造1");
	}
	static{
		System.out.println("静态1");
	}
	public Block(){
		{
			System.out.println("局部1");
		}
	}
	
	{
		System.out.println("构造2");
	}
	static{
		System.out.println("静态2");
	}
	
}

3.7.2 静态变量和实例变量的区别

在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

3.7.3 向上转型和向下转型

在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
在应用中就存在着两种转型方式,分别是:向上转型和向下转型。
比如:父类Parent,子类Child
向上转型:父类的引用指向子类对象Parent p=new Child();
说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类的方法就根据这个引用指向调用子类重写方法。
向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。

Parent  p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child)p;//此时,把Parent类型的p转成小类型Child

//其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。

3.7.4 设计多态的程序

假设现在有一个汽车类,我们可以根据汽车类创建很多汽车对象。
1、 创建汽车类。提供启动、停止、运行功能
2、 创建子类,继承汽车类。覆盖/重写 启动和停止功能
3、 创建子类对象,进行子类的功能测试
4、 创建多态对象,进行功能测试

4 面向对象4

4.1 异常

4.1.1 概述

用来封装错误信息的对象。
组成结构:类型,提示,行号。

4.1.2 异常的继承结构

Throwable - 顶级父类
– Error:系统错误,无法修复
– Exception:可修复的错误
–RunTimeException
–ClassCastException
–ClassNotFoundException

4.1.3 异常处理

程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出。
当调用了一个抛出异常的方法时,调用位置可以不做处理继续向上抛出也可以捕获异常。
1、捕获方式:

try{ 
	需要捕获的代码
}catch(异常类型  异常名){
	处理方案
}

2、抛出方式:
在会发生异常的方法上添加代码:throws 异常类型

例如:	public static void main(String[] args)  throws Exception{ }

4.1.4 测试

接收键盘输入的两个数字并做除法运算

package cn.tedu.exception;

import java.util.Scanner;

//测试异常的发生和解决
public class Test6_Exception {
	
//		接收键盘输入的两个整数并做除法运算
	public static void main(String[] args) {
		
//1,捕获异常:把可能发生异常的代码放在try里,
//当异常发生时会被catch住并执行catch中的代码执行异常处理的代码
		try {
			int a = new Scanner(System.in).nextInt();
			int b = new Scanner(System.in).nextInt();
			
			System.out.println(a/b);
		} catch (Exception e) {
			//提出解决方案
			System.out.println("您输入的两次整数有误!");
		}
		
	}
	
}

4.1.5 自定义异常

  1. 继承RuntimeException
  2. 需要的时候,直接throw异常对象
class B extends RuntimeException{
    //使用父类的处理方式
    public B(){
        super();
    }
    //使用父类的处理方法,打印异常信息
    public B(String message){
        super(message);
    }
}
public class Test {
    public static void main(String[] args) {
        //使用throw,抛出自定义异常信息
        throw new B("failure");
    }
}

4.2 访问控制符

用来控制一个类,或者类中的成员的访问范围。
类 包 子类 任意
public √ √ √ √
protected √ √ √
default √ √
private √

4.3 抽象类

4.3.1 概念

Java中可以定义没有方法体的方法,该方法由其子类来具体的实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。
抽象类可以理解为是一个只有方法声明没有方法体的特殊类。
举例:水果,东西。。
修饰符 abstract 返回值 方法名(参数列表);

class A{
	public void eat(){//声明一样,可以提取
		syso("eat...B")    }
}
class B{
	public void eat(){//声明一样,可以提取
	syso("eat。。。A")   }
}	
abstract class C{
	public abstract void eat();
}

4.3.2 特点

1、 通过java关键字abstract实现
2、 可以修饰方法或者类
3、 抽象类中可以没有抽象方法(由子类去实现)
4、 如果类中有抽象方法,那该类必须定义为一个抽象类
5、 子类继承了抽象类以后,要么还是一个抽象类,要么就把所有抽象方法都重写
6、 多用于多态中
7、 抽象类不可以被实例化

4.3.3 入门案例

package day009;

public class Test1_Animal {
	public void eat(){
		System.out.println("吃饭饭");
	}
}
/*
 * 每种动物都需要吃,
 * 发现了,方法声明都一样,只是方法体不一样
 * 
class Dog extends Test1_Animal{
	public void eat(){
		System.out.println("狗吃肉");
	}
}

class Cat extends Test1_Animal{
	public void eat(){
		System.out.println("猫吃鱼");
	}
}*/

//上面的eat()声明都一样,就是方法体不一样,那就只抽取方法声明部分。
//The type Animal must be an abstract class to define abstract methods
 abstract class Animal extends Object{
	 //This method requires a body instead of a semicolon
	public abstract  void eat();
}

 //继承抽象类,并实现抽象方法
//The type Dog must implement the inherited abstract method Animal.eat()
abstract class Dog extends Animal{
	//可以实现抽象方法,也可以子类再变成一个抽象类
}

class Cat extends Animal{
	public void eat() {
		System.out.println("猫吃鱼");
	}
	
}

4.4 抽象类的用法

4.4.1 构造函数

抽象类也有构造方法,但是不能本身实例化。
那抽象类的构造函数有啥用?一般用于给子类实例化。

package day009;

//抽象类的构造方法
public class Test2_Animal2 {

}
abstract class Animal2{
	//抽象类可以有构造方法,但是无法实例化
	//用于子类实例化
	public Animal2(){
		System.out.println("fu..Animal2()");
	}
}
class Zi2 extends Animal2{
	
}

class TestAnimal2{
	public static void main(String[] args) {
//		Animal2 a2 = new Animal2();//抽象类无法实例化 	
//		Zi2 z=new Zi2();//创建子类实例化对象

		Animal2 a2 = new Zi2();//抽象类多用于多态 	
	}
}

4.4.2 抽象类的成员变量

既可以有变量,也可以有常量。

package day009;
//成员变量
public class Test3_Animal3 {

	
}

abstract class Animal3{
	//String name;  //1
	//String name="大黄";  //2
	private String name="大黄";  //3
	public final int age=10;
	
	//3.1如果是私有变量想要取值,就提供getXxx()
	public String getName(){
		return name;
	}
}

class Zi3 extends Animal3{
	
}

class Test3Demo{
	public static void main(String[] args) {
		Animal3 a = new Zi3();//抽象类多用于多态
		//System.out.println(a.name());  //1或者2
		System.out.println(a.getName());  //3
		System.out.println(a.age);
		
	}
}

4.4.3 抽象类的成员方法

抽象类里,既可以有普通方法,有可以有抽象方法。

package day009;
//成员方法
public class Test4_Animal4{
}

abstract class Animal4{
	//抽象类中的普通方法
	public void speek(){
		System.out.println("fu...speak()");
	}
	//抽象类里的抽象方法
	public abstract void study();
}

class Zi4 extends Animal4{
	//重写抽象方法
	public void study(){
		System.out.println("zi...study()");
	}
}

class Zi4Test{
	public static void main(String[] args) {
		Zi4 z= new Zi4();
		z.speek();//fu...speak()
		z.study();//zi...study()
	}
}

4.5 分析老师示例

具体事物:培优班老师, 高手班老师
共性:备课,讲课

package day009;

public class Test5_Teacher {

}

abstract class Teacher{
	private String name;
	private int age;
	public void setName(String name){
		this.name=name;
	}
	public void setAge(int age){
		this.age=age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	public abstract void teach();
	
	public void print(){
		System.out.println(name+"........"+age);
	}
	
	
}
class CgbTeacher extends Teacher{
	public void teach() {
		System.out.println("主打互联网架构的讲解");
	}
}
class ActTeacher extends Teacher{
	public void teach() {
		System.out.println("主打高薪冲刺");
	}
}

class Test5Demo{
	public static void main(String[] args) {
		CgbTeacher ct=new CgbTeacher();
		ct.teach();ct.setName("陈子枢");ct.setAge(20);
		ct.print();
		
		
		ActTeacher at=new ActTeacher();
		at.teach();
		at.setAge(30);
		at.setName("大佬");
		at.print();
		
		Teacher t = new CgbTeacher();
		t.teach();
		t.setName("jack");
		t.setAge(10);
		t.print();	
	}
}

5 面向对象5

5.1 接口

5.1.1 概念

Java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。
Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为java结构层次上的顶层。

interface 接口名{  代码…  }

5.1.2 特点

1、 接口中都是抽象方法
2、 通过interface关键字创建接口
3、 通过implements让子类来实现
4、 可以理解成,接口是一个特殊的抽象类
5、 接口突破了java的单继承的局限性
6、 接口和类之间可以多实现,接口和接口之间可以多继承
7、 接口是对外暴露的规则,是一套开发规范
8、 接口提高了程序的功能扩展,降低了耦合性

5.1.3 入门案例

package day10;
public class T {
	public static void main(String[] args) {
		Zi z = new Zi();
		z.study();
		z.teach();
	}
}
interface Fu{
	public abstract void study();
	public abstract void teach();
}
//实现+重写
class Zi implements Fu{
	public void study(){
		System.out.println("Zi..study()");
	}
	public void teach(){
		System.out.println("Zi..teach()");
	}
}

5.2 接口的用法

5.2.1 构造方法

接口里是没有构造方法的。
在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。

interface Fu{//定义一个接口
	public abstract void show();
	//Interfaces cannot have constructors
	/*public Fu(){
		System.out.println("Fu.Fu()");
	}*/
}

5.2.2 成员变量

接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上:

public static final 
package day10;
//构造函数,成员方法,成员变量
public interface Test7_Fu {

}
interface Fu2{//定义一个接口
	
	//int num=10;//1,成员变量
	//static int num=10;//2,默认就是静态的
	//final static int num=10;//3,默认就是final的
	public final static int num=10;//4,默认就是public的

class Zi7 implements Fu2{

}

class Test7Demoo{
	public static void main(String[] args) {
		Zi7 z= new Zi7();
		//The final field Fu2.num cannot be assigned
		//z.num=30;//默认是final的,不能修改值
		System.out.println(z.num);
		System.out.println(Fu2.num);
	}
}

5.2.3 接口的成员方法

接口里的方法,默认就都是抽象的,如果你不写明是abstract的,那会自动补齐。

例如:public abstract void save
package cn.tedu.interfacedemo;
//这个类用来测试接口的使用
public class Test2_UseInter {
	public static void main(String[] args) {
		//测试
//		Inter2 in = new Inter2();//3、接口不能创建对象
		Inter2 in = new Inter2Impl();
//		in.count = 20 ;//4、是最终的,The final field Inter2.count cannot be assigned
		System.out.println(  in.COUNT   );
		System.out.println(  Inter2.COUNT );//5、是静态的
		
		in.get();
		in.update();
	}
}
//创建接口
interface Inter2{
	//1、接口里可以有构造方法吗?   ---  不能!!
//	public Inter2() {}
	
	//2、接口里可以有成员变量吗?   ---   没有!!
//public static final  int count = 10;//简写,接口会为变量自动拼接  public static final
	int COUNT = 10 ;  
	
	//3、接口里可以有成员方法吗?  --- 可以,但都是抽象方法!!
    //public abstract void update() ; // 简写,接口会为方法自动拼接 public abstract 
	void update() ; // 简写,接口会为方法自动拼接 public abstract 
	void get() ;
}
class Inter2Impl  implements  Inter2{
	@Override
	public void update() {
		System.out.println("update()...");
	}
	@Override
	public void get() {
		System.out.println("get()...");
	}
}

5.3 接口的复杂用法

Java中单继承的局限性通过接口可以解决。
接口可以多继承也可以多实现,甚至可以继承的同时多实现。

package cn.tedu.interfacedemo;

//这个类用来测试接口的复杂用法:多继承多实现
public class Test4_ComInter {
	public static void main(String[] args) {
		Interface1 in = new Interface1Impl();
		in.save();
		in.update();
	}
}
//创建接口1
interface Interface1{
	void save();
	void update();
}
//创建接口2
interface Interface2{
	void get();
	void delete();
}
//1、打破了java单继承的局限性,因为接口之间可以多继承,多个接口之间逗号隔开
interface Interface3 extends Interface1,Interface2{
	void add();
}
//3、接口还可以多实现吗??---可以多实现,只不过接口之间逗号隔开
class ManyImpl implements  Interface1,Interface2{
	public void save() {}
	public void update() {}
	public void get() {}
	public void delete() {}
}
//4、接口可以继承的同时,多实现?? -- 
class MoreImple extends ManyImpl  implements Interface1,Interface2  {
}
//2、创建实现类,使用3号接口的功能,需要重写几个方法呢??---同时重写1号和2号和3号接口里的所有功能
class Interface3Impl  implements Interface3{
	@Override
	public void save() {  }
	@Override
	public void update() {  }
	@Override
	public void get() {  }
	@Override
	public void delete() {	}
	@Override
	public void add() {	}
}
//TODO 创建实现类
class Interface1Impl implements Interface1{
	@Override
	public void save() {
		System.out.println("save()...");
	}
	@Override
	public void update() {
		System.out.println("update()...");
	}
}

5.4 总结

1、类和类的关系:继承 extends / 单继承 / 单根继承
– 继承的意义:为了提高代码的复用性,减少了代码的编写提高开发效率。
– 方法重写的意义:在不修改父类源码的前提下,在子类中重写业务,从此使用的就是重写后的功能。
– 要求子类的方法声明和父类一样,只要改方法体。
– 有了继承有了重写就产生了多态,多态的意义:为了统一程序的调用标准,标准就是父类。
– 多态 也就是向上转型/向上造型。
– 向下造型的意义:很少用,相当于想要使用子类的特殊功能,还不如直接创建子类对象简单。
– class A extends B
– 其中,A和B都是类,A是子类,B是父类,A就拥有了B的所有功能(除了私有的和构造方法)

-- 其他知识点:this 和super  ,构造方法,各种代码块...

2、类和接口关系:实现implements / 单实现 / 多实现
– class A implements B,C
– 其中,A是实现类,B和C是接口
– 要求A 可以把 B 和C 接口里的所有 抽象方法 都重写掉,否则 A 就是抽象类
– 接口不能创建对象
– 接口里没有构造方法,接口里都是常量,接口里都是抽象方法

3、接口和接口关系:继承extends / 单继承 / 多继承
– 接口的多继承的关系,打破了java单继承的局限性
– interface A extends B,C
– 其中,A B C 都是接口,A是子接口,同时拥有B和C接口里的所有功能
– class AImpl implements A
– 要求AImpl需要重写A接口里的所有方法(是包含B和C接口的所有方法),否则就是抽象类

4、接口和抽象类的区别!!!
– 相同点:都是抽象层,都不能实例化
– 不同点:
– 1、抽象类用abstract关键字描述,接口用interface
– 2、子类和抽象类之间是extends关系,实现类和接口之间是implements关系
– 3、抽象类中 可以 有构造方法 ,接口里 不能 出现 构造方法
– 4、抽象类里可以有 变量,接口里没有变量全都是静态的常量
– 5、接口里定义常量的语法:public static final String NAME=“jack”,会为变量自动拼接public static final
– 6、抽象类里 可以有普通方法 也可以有 抽象方法,接口都是抽象方法
– 7、抽象类和子类之间是继承关系,而且java中,只支持单继承
– 8、接口突破了java单继承的局限性,因为接口可以多继承也可以多实现,甚至可以继承的同时多实现
– 9、接口的复杂用法
– 多继承: interface A extends B,C 其中A是子接口,同时拥有自己的和BC的功能
– 多实现: class AImpl implements M,N,O,P 其中AImpl是实现类,需要同时重写MNOP的所有抽象方法,否则就是一个抽象类
– 继承的同时多实现: class AImpl extends Object implements M,N 一定是先继承后实现

5.5 设计模式

Java中有23 种设计模式,本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性,以及类的关联关系和组合关系的充分理解。
当然,软件设计模式只是一个引导,在实际的软件开发中,必须根据具体的需求来选择。
1、 对于简单的程序,可能写一个简单的算法要比引入某种设计模式更加容易。
2、 但是对于大型项目开发或者框架设计,用设计模式来组织代码显然更好。

5.5.1 单例设计模式概念

单例模式可以说是大多数开发人员在实际中使用最多的,常见的Spring默认创建的bean就是单例模式的。
单例模式有很多好处,比如可节约系统内存空间,控制资源的使用。
其中单例模式最重要的是确保对象只有一个。
简单来说,保证一个类在内存中的对象就一个。
RunTime就是典型的单例设计,我们通过对RunTime类的分析,一窥究竟。

5.5.2 源码剖析

/**
 * Every Java application has a single instance of class
 * Runtime that allows the application to interface with
 * the environment in which the application is running. The current
 * runtime can be obtained from the getRuntime method.
 * 

* An application cannot create its own instance of this class. * * @author unascribed * @see java.lang.Runtime#getRuntime() * @since JDK1.0 */ RunTime.java package java.lang; public class Runtime { //1、创建静态的全局唯一的对象 private static Runtime currentRuntime = new Runtime(); //2、私有构造方法, /** Don't let anyone else instantiate this class */ private Runtime() {} //3、通过自定义的静态方法获取实例 public static Runtime getRuntime() { return currentRuntime; } }

5.5.3 饿汉式

目的:控制外界创建对象的个数只能创建1个对象
开发步骤:
1、 私有化构造方法
2、 在类的内部创建好对象
3、 对外界提供一个公共的get(),返回一个已经准备好的对象

package cn.tedu.single;
//测试单例设计模式	
public class Test8_Single {
	public static void main(String[] args) {
		Single s = Single.get();
		Single s1 = Single.get();
		
		//get()多少次,内存中使用的都是同一个对象
		System.out.println(s);//cn.tedu.single.Single@15db9742
		System.out.println(s1);//cn.tedu.single.Single@15db9742
	}
}
class Single{
//	1、私有化构造方法,不让外界直接new
	private Single() {}
	
//	2、在类的内部,创建好对象
	//static :静态只能调用静态
	static private  Single s = new Single();
	
//	3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法	
	static public Single get(){
		//注意:静态只能调用静态
		return s;
	}
}

5.5.4 懒汉式

class Single{
//	1、私有化构造方法,不让外界直接new
	private Single() {}
	
//	2、在类的内部,创建好对象
	//static :静态只能调用静态
	static private  Single s = null;
	
//	3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法	
synchronized	static public Single get(){
		//注意:静态只能调用静态
		if(s==null){
           s = new Single();//会有安全问题
}
		return s;
	}
}

5.6 拓展

5.6.1 abstract注意事项

抽象方法要求子类继承后必须重写。那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。
1、 private:被私有化后,子类无法重写,与abstract相违背。
2、 static:静态的,优先于对象存在。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。
3、 final:被final修饰后,无法重写,与abstract相违背。

5.6.2 接口和抽象类的区别

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
7、抽象类里可以没有抽象方法,如果要扩展抽象类的新方法,子类将很容易的就能得到这些新方法。
8、如果一个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可继承接口,并可多继承接口,但类只能单根继承。

5.6.3 设计学员示例

具体事物:培优班学员,高手班学员
共性:姓名,学号,学习方法,休假方法
利用面向抽象 、 面向接口的编程思想,完成程序设计。

5.6.4 了解软件设计的开闭原则OCP

开放功能扩展,关闭源码修改。等
开闭原则的英文全称是Open Close Principle,缩写是OCP,它是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。
开闭原则的定义是:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。
开闭原则,是一种设计模式,随着面向对象程序设计的思想,应运而生。
开,指的是可以在源代码的基础上进行扩展,比如继承,接口,抽象类等。在JAVA中,之所以用继承,是在可以直接调用类库的前提下,对其功能进行扩展。不需要应用者去了解封装类的内部逻辑就可以做开发。
闭:指不允许对原有的代码进行修改。以免影响其他现有功能,造成功能瘫痪。

你可能感兴趣的:(javase,java,开发语言,后端)