文章目录
1.知识回顾
* 面向对象的两个概念:类和对象
* 类:描述相同事物的共同特征的抽象
* 对象:是具体实现的实体,是真实的
* 在代码层面:必须现有类,才能创建出对象
*
*
* 定义类的格式:
* 修饰符 class 类名{
* // 1.成员变量
* // 2.成员方法
* // 3.构造器 constructor初始化一个类的对象并返回引用
* // 4.代码块
* // 5.内部类
*
* }
* 注意:
* 类名的首字母应该大写,满足"驼峰写法"
* 一个java代码文件中可以定义多个类, 但是只能有一个类是用public修饰的,而且public修饰的类名必须是代码的文件名
*
* 类的成分研究
* 类有五大成分(五大金刚), 如上
* 注意:只要不是这五大成分放在类下就会报错
*
*
* 构造器的复习:
* 作用:初始化一个类的对象并返回引用
* 格式:
* 修饰符 类名(形参){
*
* }
* 构造器初始化对象的格式:
* 类名 对象名 = new 构造器;
* 注意:一个类默认会自带一个无参构造器,即使不写也存在,但是自己写了一个构造器,那么默认的无参构造器就被覆盖了!!
public class ClassDemo01 {
public static void main(String[] args) {
}
}
class Student{
private String name;
public Student(String name){
this.name = name;
}
}
2.this关键字
* this关键字的作用:
* this代表了当前对象的引用
*
* this关键字可以用在实例方法和构造器中
* this用在方法中,那么谁调用这个方法,this就代表谁
* this在构造器,代表了构造器正在初始化的那个对象的引用
public class ThisDemo02 {
public static void main(String[] args) {
Animal a1 = new Animal("dog",1,'0');
System.out.println(a1);
}
}
class Animal{
private String name;
private int age;
private char sex;
public Animal(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
3.面向对象三大特性
* 面向对象三大特征:封装,继承,多态
* 特征:特点,是Java语言的风格,在开发中必须遵循,即使毫无意义,代码按照这个风格写
*
* 封装的作用:
* 1.提高安全性
* 2.可以实现代码的组件化,get,set
* 封装的规范:
* 1.成员变量私有,private修饰的方法,变量,构造器,只能在本类使用
* 2.提供成套的getter+setter方法暴露成员变量的取值和赋值,public是公开的
* 小结:
* 封装的核心思想:合理隐藏,合理暴露。
* 封装已经成为Java代码的风格,即使代码毫无意义,还是要按照封装的规范写代码
*
4.static关键字
* Java中这些成员变量或者方法是存在所属性的
* 有些属于对象,有些是处于类本身的
*
* Java是通过成员变量是否有static修饰来区分是处于类还是对象
*
* 按照是否有static修饰,成员变量和方法可以分为:
* 1.静态成员变量(类变量)
* 2.实例成员变量
*
* 1.静态方法,属于类本身,直接用类名访问即可
* 2.实例方法,属于类的每个对象的,必须用类的对象来访问
*
* 小结:
* static成员变量与类一起加载一次,直接用类名调用
* 实例成员变量,与类对象一起加载,对象有多少个,实例成员变量就加载多少份
5.成员变量和成员方法访问拓展
* a. 实例方法是否可以直接访问实例成员变量?当然!
* b. 实例方法是否可以直接访问静态成员变量?yes!静态成员变量可以别共享访问
* c. 实例方法是否可以直接访问实例方法? 当然!
* d. 实例方法是否可以直接访问静态方法? yes! 静态方法可以共享访问
* -----------------------------------------
*
* a. 静态方法是否可以直接访问实例变量?不可以!实例变量必须用对象访问!
* b. 静态方法是否可以直接访问静态变量?当然
* c. 静态方法是否可以直接访问实例方法?不可以!实例方法必须用对象访问!
* d. 静态方法是否可以直接访问静态方法?当然
*
6.继承
* 继承是java中一般到特殊的关系,是一种子类到父类的关系
*
* 被继承的类称为 父类、超类
* 继承的类称为: 子类
*
* 继承的作用:
* 提高代码的复用,相同的代码可以定义在父类中
* 子类直接继承父类,就可以直接使用父类的这些代码了,相同代码重复利用
*
* 子类更强大,不仅有父类的功能,还有自动机的功能
*
* 格式:
* 子类 extends 父类{
*
* }
*
*
* 小结:
* 继承是子类到父类的一种关系
* 子类继承了一个父类,子类就可以直接得到父类的属性和行为了
* 在Java中继承是"is a" 的关系, cat extends animal,猫是一个动物
* 在Java中,子类更强大,子类不仅有父类的功能还有自己的功能
public class ExtendsDemo {
}
class Animal{
}
class Cat extends com.kcl._06继承的概述.Animal {
}
6.1继承案例
* 案例
* 学生类: 姓名,年龄,吃饭, 学习
* 老师类: 姓名,年龄,吃饭, 授课
* 班主任: 姓名,年龄,吃饭, 管理
*
*
* 小结:
* 继承的优势:可以把相同的代码定义在父类,子类可以直接继承使用
* 提高代码的复用性,相同代码在父类中写一次就可以了
public class TestMain {
public static void main(String[] args) {
Student s = new Student();
s.setName("s1");
s.eat();
s.study();
Teacher t = new Teacher();
t.setName("t1");
t.teach();
}
}
class Student extends People{
public void study(){ System.out.println(this.getName() + "学生认真学习--"); }
}
class Teacher extends People{
public void teach(){ System.out.println(this.getName() +"老师在授课"); }
}
class Monitor extends People{
}
class People{
private String name;
private int age;
public void eat(){
System.out.println(name + "在吃饭");
}
}
6.2子类不能继承父类的东西
* 子类不能继承父类的东西:
* 子类不能继承父类的构造器! 构造器是不能继承的
* 子类是否可以继承父类的私有成员? --可以继承,只是不能直接访问! 以后可以暴力访问
* 子类是否可以继承父类的静态资源?
* -- 虽然可以访问,但是子类不能继承父类的静态资源
* -- 父类的静态资源只有一份,属于父类
* -- 子类只是可以访问父类的静态资源,父类的静态资源只有一份,只是可以共享访问并非继承!
*
*
* 小结: 非静态成员,非静态方法,可以继承(赋值一份)
* 静态资源只有一份,可以访问,并非继承
public class ExtendsDemo {
public static void main(String[] args) {
Cat c = new Cat();
System.out.println(c.age);
// System.out.println(c.name); 儿子继承爸爸的保险柜,却打不开,以后可以暴力访问继承自父类的私有成员
c.run();
}
}
class Cat extends Animal{
}
class Animal{
public static int age = 100;
private String name;
public void run(){
}
}
6.3继承后成员变量的特点
* 就近原则:
* 方法中找方法变量,子类有找子类,父类没有就报错
*
* 小结:
* this代表当前对象的引用,可以用于访问当前子类的成员变量,成员方法
* super代表父类对象的引用,可以访问父类的成员变量
*/
public class TestDemo {
public static void main(String[] args) {
Cat cat = new Cat();
cat.show();
}
}
class Animal{
public String name = "动物名称";
}
class Cat extends Animal{
public String name = "子类名称";
public void show(){
String name = "局部名称";
System.out.println(name); //局部名称,如果不限定,就近原则
System.out.println(this.name); //子类名称
System.out.println(super.name); // 父类名称
}
}
6.4继承后成员方法访问特点
* 描述 也是就近原则
*
* 子类继承的成员方法,访问也是就近原则
*
* 子类对象优先使用子类的方法,没有则找父类,父类没有就报错
*
*/
public class TestDemo {
public static void main(String[] args) {
Cat c = new Cat();
c.run();
c.eat();
}
}
class Animal{
public void run(){
System.out.println("动物可以跑");
}
public void eat(){
System.out.println("动物在吃");
}
}
class Cat extends Animal {
public void run(){
System.out.println("🐱可以跑");
}
}
6.5继承后方法重写
* 方法重写的概念:
* 子类继承了父类,但是觉得方法无法满足自己的需求
* 子类重写一个与父类声明一样的方法来覆盖父类的该方法,子类的这个方法就进行了方法重写
*
* @override注解
* 方法一旦加入这个注解,那就必须是成功重写这个方法,否则报错
* @override优势:可读性好,安全,优雅!
*
* 方法重写的要求:
* 1.重写方法名和形参必须与父类一致
* 2.返回类型也要和父类一致 或者 比父类返回值类型小
* 3.方法修饰符和父类一致 或者 比父类方法修饰符大
* 4. 子类重写方法申明抛出的异常应该与父类被重写方法申明抛出的异常一样或者范围更小!
*
* 方法重写的规范
* 1.加上@override
* 2.申明不变,重新实现
*
*
* 小结:
* 方法重写建议加上@Override注解
* 方法重写核心要求,方法名称和阐述列表和父类申明一致!
*
*
*
*/
public class ExtendsDemo {
public static void main(String[] args) {
Wolf w = new Wolf();
w.run();
}
}
class Wolf extends Animal{
@Override //重写父类方法,不写这个也可以,但是保证和父类的方法名和形参 一致
public Integer run() {
System.out.println("🐺跑的贼快");
return 1;
}
}
class Animal{
protected Object run(){
System.out.println("动物跑");
return null;
}
}
6.6super关键字
* super代表了父类的引用
* super可以用在子类的实例方法中调用父类的方法
public class ExtendsDemo02 {
public static void main(String[] args) {
SportMan sportMan = new SportMan();
sportMan.run();
sportMan.go(); //另辟蹊径
}
}
class SportMan extends People{
@Override
public void run() {
System.out.println("运动员在跑");
}
public void go(){
super.run(); //父类的
run(); //子类的
}
}
6.7继承后私有方法和静态方法都不能重写
* private成员变量可以继承,但不能直接访问
* private成员方法不可以继承,所以不能访问
* 至少是 protected public方法, 才可以重写方法
*
*
* 静态方法没有给到子类,不能重写,可以单独写一个,可以重名
*
*/
public class ExtendsDemo03 {
}
class Mac extends Computer{
@Override
public void go() {
}
public void up(){
}
}
class Computer{
public void go(){
}
private void close(){
}
}
6.8继承后的构造器特点
* 继承后构造器的特点
*
* 特点:子类构造器第一行默认一定会先访问父类的无参构造器,再执行子类自己的构造器
*
* why?1.子类构造器,第一行 默认存在 super();
* 2. 子类继承父类,子类就得到了父类的属性和行为
* 当我们调用子类构造器初始化子类对象数据的时候,必须先调用父类无参构造器初始化继承自父类的属性和方法
* 先初始化爸爸的成员变量!
*
*
* ------------------------------------------------------------------------------------
* 继承: 成员变量都继承,成员方法private修饰不能继承! 构造器不继承,且子类会先调用父类构造器!
* ------------------------------------------------------------------------------------
public class TestDemo {
public static void main(String[] args) {
Cat cat = new Cat(); //父类Animal无参构造器 子类cat无参构造器
}
}
class Cat extends Animal{
public Cat(){
super(); // 默认存在,调用父类无参构造器
System.out.println("子类cat无参构造器");
}
}
class Animal{
public Animal(){
System.out.println("父类Animal无参构造器");
}
}
6.9super
**
* 特点: 子类的全部构造器默认一定会调用父类的无参构造器
* super(...) 可以根据参数选择调用父类的某个构造器
*
*
* this(...) 也可以这个样子使用
* 调用本类的其他构造器
*
* 注意: this(...) super(...)必须放在构造函数的第一行,否则报错!
* 所以 this和super不能同时出现
public class TestDemo {
public static void main(String[] args) {
Monkey monkey = new Monkey("大猴子",2,'0');
monkey.eatBanana();
}
}
class Monkey extends Animal{
public Monkey(char sex){
this("123",2,sex);
}
// 有些成员变量在 父类 里面
public Monkey(String name, int age, char sex){
super(name,age,sex); // 根据参数匹配调用父类构造器
}
public void eatBanana(){
System.out.println(this.getName() + " " + this.getAge() + " " + this.getSex() + " 在吃🍌🍌");
}
}
class Animal{
private String name;
private int age;
private char sex;
}
6.10继承的特点
* 继承的特点
* -----------------------------------
* 1.单继承:一个类只能继承一个直接父类
* -----------------------------------
* why? 反正法,加入Java可以多继承,请看如下代码
* class A{
* public void test(){
* System.out.println("A");
* }
* }
*
* class B{
* public void test(){
* System.out.println("B");
* }
* }
* class C extends A,B{
* public static void main(String args[]){
* C c = new C();
* c.test(); //出现了类的二义性!
* }
* }
*
*-----------------------------------
* 2.多层继承:一个类可以间接继承多个父类(家谱)
* 3.一个类有多个子类
* 4.一个类要么默认继承了Object类,妖魔间接继承了Object类,Object类是Java中的祖宗类!
*
public class ExtendsDemo {
}
class A{}
class B{}
class C extends A{
}
7.抽象类
7.1抽象类概述
* 什么是抽象类?
* 父类知道子类一定要完成某个功能,但是每个子类完成的情况是不一样的
* 子类以后会用自己重写的功能,那么服务里该功能就可以定义成抽象方法,子类重写自己的就可以了
* 抽象类必须用abstract修饰
*
* 什么是抽象方法:
* 没有方法体,只有方法签名,必须用abstract修饰
* 拥有抽象方法的类必须定义成抽象类
* 抽象类: 拥有抽象方法的类必须定义成抽象类,抽象类必须用abstract修饰
public class AbstractDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.run();
}
}
class Cat extends Animal{
@Override
public void run() {
System.out.println("🐈跑");
}
}
class Dog extends Animal{
@Override
public void run() {
System.out.println("🐶跑");
}
}
abstract class Animal{
// 子类要完成这个功能,但是由子类自己重写完成
// 抽象方法,没有方法体只有方法签名,必须用abstract修饰
public abstract void run();
}
7.2抽象类的使用
* 抽象类的使用
*
* 抽象类作用: 为了被子类继承, 不然就没有意义
*
* 小结: 抽象类是为了被子类继承,约束子类要重写抽象方法
*
* 一个类继承了抽象类,必须重写抽象类的全部抽象方法,否则这个类也必须定义成抽象类(一般不会这样干)
*
public class AbstractDemo {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.work();
Manager manager = new Manager();
manager.work();
}
}
7.3抽象类的特征
* 特征:有得有失!
* 有得:抽象类得到了拥有抽象方法的能力
* 有失:抽象类失去了创建对象的能力(抽象类不能创建对象)
*
* 面试题:
* 抽象类是否有构造器,抽象类是否可以创建对象?
*
* 答:抽象类作为类一定有构造器,而且抽象类必须有构造器
* 提供给子类创建对象调用父类构造器使用的
*
* 答:抽象类不能创建对象,虽然有构造器
* 反正法: 加入抽象类可以创建对象
* Animal a = new Animal();
* a.run(); //抽象方法不能执行,因为没有方法体,所以抽象类不能创建对象
*
* 抽象类本身意味着抽象,抽象不能具体化。
*
* =============================================
* 注意: 抽象类有得有失,但是类的特性 抽象类全都有
* 抽象类不能创建对象,抽象类可以包含抽象方法,除此之外类有的成分,抽象类都包含
*
* =============================================
public class AbstractDemo {
public static void main(String[] args) {
}
}
abstract class Animal{
private String name;
public Animal(){
}
public void test(){
}
public abstract void run();
}
7.4抽象类存在的意义
* 抽象类这个概念,你可以用,也不可以用!
*
* 抽象类存在的意义有两点:
* 1. 抽象类就是为了被子类继承(就是为了派生子类),否则抽象类毫无意义(基本准则)(抽象类不能创建对象)(生孩子机器)
*
* 2. 抽象类体现的是模板思想,部分实现,部分抽象。 可以设计模板设计模式
*
*
*/
7.5模板设计模式
* 什么是设计模式? 设计模式是前人或者技术大牛或软件行业 在生产实践中发现的优秀软件设计架构和思想
* 后来者可以直接用这些架构和思想可以设计出优秀,提高效率,可扩展性,可维护性的软件!
*
*
* 模板设计模式就是一个经典的设计模式思想
*
* 模板设计模式的作用: 优化代码架构,提高代码的复用性,相同功能的重复代码无需反复写,可以做到部分实现部分抽象,抽象的东西交给使用模板的人来写
*
* 作文模板:
* 标题固定: 《我的爸爸》
* 第一段固定: 请介绍一下你的爸爸,说说你的爸爸有多好
* 正文部分: 抽象出来
* 结尾部分: 我的爸爸真棒.....
public class AbsstractDemo {
public static void main(String[] args) {
Student student = new Student();
student.write(); // 优先调用子类的方法,子类没有找父类,父类没有就报错
Teacher teacher = new Teacher();
teacher.write();
}
}
// 设计一个模板类
abstract class Template{
private String title = "\t\t\t\t《我的爸爸》";
private String one = "\t请介绍一下你的爸爸,说说你的爸爸有多好";
private String last = "\t我的爸爸真棒.....";
// 写作文的功能
public void write(){
System.out.println(title);
System.out.println(one);
//正文部分,模板不能确定,交给使用模板的子类来写
System.out.println(writeMain());
System.out.println(last);
}
// 定义抽象方法描述正文
public abstract String writeMain();
}
//使用模板
class Student extends Template{
@Override
public String writeMain() {
return "\t学生写的文章正文内容";
}
}
class Teacher extends Template{
@Override
public String writeMain() {
return "\t老师写的文章正文内容🏃🤪🤪🧛♀️🧛♀️🧛♂️";
}
}
7.6抽象类注意事项和总结
* 1.抽象类不能创建对象,如果创建,编译无法通过报错,只能创建非抽象子类的对象
*
* 2.抽象类一定有且必须有构造器,提供子类创建对象时,初始化父类成员使用的
*
* 3.抽象类不一定包含抽象方法,但是有抽象方法的类必须是抽象类
*
* 4.抽象类的子类,必须重写父类中所有的抽象方法,否则子类必须定义成抽象类
*
* 5. 抽象类存在的意义就是被子类继承,抽象类体现的思想就是模板思想
* 抽象类中已经实现的是 模板中确定的成员
* 抽象类不确定如何实现的方法定义成抽象方法,交给具体的子类实现
*
*
* ===========================================
* 抽象类构造器 从语法上来说可以私有,但是没有意义
* ===========================================
8.接口
8.1接口的概述
* 接口是更加彻底的抽象,接口中全部是抽象方法(JDK8之前,接口中只能是抽象方法和常量), 接口同样是不能创建对象的
*
* 接口体现的的是规范思想!实现接口的子类必须重写接口的全部抽象方法。
*
* 接口的定义格式:
* 修饰符 interface 接口名{
*
* }
*
* 接口的成分研究:
* JDK8之前,接口中只能是抽象方法和常量
*
*
* 小结:接口体现的规范思想
* JDK1.8之前,接口中只有抽象方法和常量
* 接口中抽象方法 public abstract 可以不写默认加上
* 接口中常量 public static final 可以不写默认加上
* 除此之外没有其他成分!
*
*/
public interface InterfaceDemo {
// 1. 抽象方法
// 接口中的抽象方法可以省略 public abstract不写,默认会加上!!! 而抽象类中不能省略
public abstract void run();
public void run1(); // 都会变成 public abstract
// 2.常量,变量值只有一个,而且在程序运行的过程中不可以更改
// 一般修饰符是: public static final
// 常量的变量名称字母 建议全部大写,多个单词用"——"连接
// 接口中的常量可以省略 public static final 不写,默认会加上 !!!!!!!!
public static final String SCHOOL_NAME = "黑马";
}
interface Animal{
}
8.2接口的基本实现
* 子类 继承 父类
* 实现类 实现 接口
*
* 类与类是继承关系,接口和接口是实现关系
* 实现接口的类成为:实现类
*
* 实现类的接口的格式:
*
* 修饰符 class 类名 implements 接口1,接口2,接口3{
*
*
* }
* 小结:一个类必须重写完接口中的全部抽象方法,否则这个类要定义成抽象类(一般不会这样做)!
public class InterfaceDemo{
public static void main(String[] args) {
PingPongMan pingPongMan = new PingPongMan("zjk");
pingPongMan.competition();
pingPongMan.run();
}
}
class PingPongMan implements SportMan{
private String name;
public PingPongMan(String name ){
this.name = name;
}
@Override
public void run() {
System.out.println(name + "乒乓运动员跑");
}
@Override
public void competition() {
System.out.println(name + "乒乓运动员比赛");
}
}
interface SportMan{
void run();
void competition();
}
8.3接口的多实现
* 小结: 一个类实现多个接口,必须重写全部接口中的抽象方法,否则这个类要定义为抽象类(一般不这样做)
public class InterfaceDemo {
public static void main(String[] args) {
BasketBall yaoming = new BasketBall();
yaoming.rule();
yaoming.competition();
yaoming.run();
}
}
class BasketBall implements SportMan,Law{
@Override
public void run() { }
@Override
public void competition() { }
@Override
public void rule() {}
}
interface SportMan{
void run();
void competition();
}
interface Law{
void rule();
}
8.4接口与接口的多继承
* 目标: 接口与接口的多继承
*
* 引入:类与类是单继承关系
* 类与接口是多实现关系,一个类可以同时实现多个接口
* 接口与接口是多继承关系: 一个接口可以同时继承多个接口
*
*
*/
public class InterfaceDemo {
}
class PingPongMan implements SportMan{
@Override
public void run() {}
@Override
public void competition() {}
@Override
public void rule() {}
@Override
public void abroad() {}
}
//=================================
// 接口与接口的多继承,用一个接口合并多个接口
interface SportMan extends Law,Go{
void run();
void competition();
}
interface Law{
void rule();
}
interface Go{
void abroad();
}
8.5JDK1.8之后接口新增方法
* Jdk 1.8之后接口新增的三个方法(sun公司),了解即可
*
* 1.8之前 抽象方法+常量
* 1.8之后 新增了三个方法:
* 1.默认方法,就是实例方法,
* 必须用default修饰,默认会加上public修饰,
* 只能用接口的实现类对象来调用
*
* 2.静态方法
* 直接加上static修饰
* 默认会加上 public修饰
* 接口的静态方法只能用接口的类名称本身进行调用,别无他法
* 3.私有方法(1.9开始才支持)
* 其实就是私有实例方法,必须private修饰
* 只能在本接口中使用,比如default实例方法调用
*
*/
public class InterfaceDemo {
public static void main(String[] args) {
SportMan.inAddr(); //调用接口中的静态方法
PingPongMan zjk = new PingPongMan();
zjk.run(); //调用接口中的实例方法
}
}
interface SportMan{
// 默认用public修饰,可以不用写 public
public default void run(){
System.out.println("跑的贼快");
}
// public 可省略
// 只能本接口调用
public static void inAddr(){
System.out.println("我在地球");
}
// 私有方法,私有的实例方法
// 通常是给[私有方法] 或者 [默认方法调用的]
private void go(){
// 只能在本接口中使用
}
default void go2(){
go();
}
}
class PingPongMan implements SportMan{
}
8.6实现多个接口的注意事项
*
* 拓展: 实现多个接口的使用注意事项(非常偏的语法,理解和了解即可)
*
* 1. 如果实现了多个接口,多个几口中存在同名的静态方法并不会冲突
* 原因是只能通过各自接口名访问静态方法
*
* 2.当一个类,既继承一个父类,又实现若干个接口时(重点)
* 父类的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法
*
*
* 3.当一个类实现多个接口时,多个接口中存在同名的默认方法,实现类必须重写这个方法
*
* 4,接口中,没有构造器,不能创建对象(重点)
* 接口是更彻底的抽象,连构造器都没有,自然不能创建对象
*
*/
9.代码块
静态代码块
import java.util.ArrayList;
import java.util.List;
目标: 静态代码块研究(重点)
* 类有5大成分: 成员变量,方法,构造器,代码块,内部类
*
* 代码块按照有无static修饰可以分为:静态代码块,实例代码块
*
* (1)静态代码块:属于类,会和类一起加载,而且自动触发执行一次!
* static{
* content
* }
* 静态代码块可以用于执行类方法之前进行静态资源初始化操作
public class CodeDemo01 {
public static List<String> strs = new ArrayList<>();
//加载类时就触发
static{
strs.add("str01");
strs.add("str02");
strs.add("str03");
System.out.println("静态代码块");
}
public static void main(String[] args) {
}
}
实例代码块
package com.kcl._13代码块;
* 示例代码块
* 格式: {}
* 无static修饰,会与类的每一个对象一起加载,每次创建对象的时候加载
* 实例代码块的代码实际上是提取到每个构造器中去执行
public class CodeDemo02 {
private String name;
//初始化实例对象, 一般不会这样做
{
name = "jack";
System.out.println("示例代码块");
}
public static void main(String[] args) {
new CodeDemo02();
new CodeDemo02();
}
}
10.Final关键字
* final 可以修饰 类,方法,变量
*
* (1) final修饰类:类不能被继承了, 把类结扎了
* 什么时候类用final? 牛逼的类用final,一般不用
* (2) final修饰方法,方法不能别重写。
* 什么时候用? 该方法已经很完美了
* (3) final修饰变量,变量有且仅能被赋值一次。
* 成员变量:
* 静态成员变量
* 实例成员变量
* 局部变量(不想更改,更专业一点)
*
* 拓展:请问abstract 和 final的关系是什么?
* 互斥关系! 不能同时出现修饰成员
* 一个要别继承,一个不能别重写!
public final class FinalDemo01 {
public static void main(String[] args) {
final int age = 10; //不能被修改
final double rate = 3.14;
}
public static void buy(final double r){
//r = 0.1; 报错,第二次赋值了
}
}
class Animal{
public final void run(){
}
}
class Wolf extends Animal{
}
final修饰静态成员变量
* final修饰静态成员变量,即常量
*
* 拓展:
* final修饰静态成员变量可以在那些地方赋值?
* 1.定义的时候赋值一次
* 2.可以在静态代码块中赋值一次
public class FinalDemo02 {
public static final String SCHOOL_NAME;
static{
SCHOOL_NAME = "ustc";
}
public static void main(String[] args) {
// SCHOOL_NAME = "ustc"; 报错第二次赋值
}
}
final修饰实例成员变量
* final修饰实例成员变量(了解,用不到)
*
* 拓展:
* final修饰实例成员变量可以在那些地方赋值1次:
* 1.定义的时候赋值一次
* 2.可以在实例代码块中赋值一次
* 3.可以在每个构造器中赋值一次
*
public class FinalDemo03 {
private final String NAME = "pku"; //意义不大,每个对象的成员变量值不同
private final int age;
private final char sex;
{
sex = '0'; // 等同于构造器
}
public FinalDemo03(){
age = 1;
}
}
11.单例设计模式
饿汉模式
* 什么是单例?(面试重点,常考)
* 单例的意思是一个类永远只存在一个对象,不能创建多个对象
*
* 为什么要用单例?
* 开发中有很多类的对象,我们只需要一个,例如虚拟机对象,任务管理器对象
* 对象越多,越占内存,有时候只需要一个对象就可以实现业务
* 单例可以节约内存,提高性能
*
* 如何实现单例?
* 单例的实现方式总共有8中
* 1.饿汉单例模式
* 通过类获取单例对象的时候,对象已经提前做好了
*
public class SingleInstanceDemo01 {
public static void main(String[] args) {
SingleInstance01 instance = SingleInstance01.getInstance();
}
}
class SingleInstance01{
private static SingleInstance01 INSTANCE = new SingleInstance01();
public static SingleInstance01 getInstance(){
return INSTANCE;
}
// 1.构造器四有,构造器只能勒种访问
private SingleInstance01(){}
}
懒汉模式
* 懒汉单例模式
* 吃包子的时候再去做包子
public class SingleInstanceDemo02 {
public static void main(String[] args) {
SingleInstance02 instance = SingleInstance02.getInstance();
}
}
class SingleInstance02{
private SingleInstance02(){}
// 懒汉单例不能直接创建对象,必须需要的时候才创建
private static SingleInstance02 INSTANCE;
public static SingleInstance02 getInstance(){
if(INSTANCE == null)
INSTANCE = new SingleInstance02();
return INSTANCE;
}
}
12.枚举
* 枚举类的作用?
* 枚举是用于做信息标志和信息分类
*
* 枚举类的格式:
* 修饰符 enum 枚举名称{
* // 第一行罗列的必须是枚举类的对象名称
* }
*
* 反编译后的枚举源代码
* public final class Sex extends java.lang.Enum<Sex>{
* public static final Sex BOY = new Sex();
* public static final Sex GIRL = new Sex();
* public static sex[] values();
* public static Sex valueOf(java.lang.String);
* static();
* }
*
* 枚举类特点:
* 1. 枚举类是final修饰的,不能被继承
* 2. 枚举类默认聚成了枚举类型: java.lang.Enum<Sex>
*
* 3. 枚举类第一行罗列的是枚举类对象,而且是用常量存储的
* 4. 所以枚举类第一行写的都是常量名称,默认存储了枚举对象
* 5. 枚举类的构造器默认是私有的
* 6. 枚举类相当于是多例模式(类比于单例模式)
public class EnumDemo01 {
public static void main(String[] args) {
Sex boy = Sex.BOY;
Sex girl = Sex.GIRL;
System.out.println(boy); // 底层重写了
System.out.println(boy.ordinal()); // 枚举对象的索引位置
}
}
enum Sex{
BOY, GIRL;
}
实例
* 枚举是用于做信息标志和信息分类: 优雅
*
* 小结:建议以后做信息标志和信息分类采用枚举
public class EnumDemo02 {
public static void main(String[] args) {
move(Oritation.LEFT);
}
// 控制玛丽的移动
public static void move(Oritation oritation){
switch (oritation){ // switch自动识别类型
case UP:
System.out.println("↑"); break;
case DOWN:
System.out.println("↓"); break;
case LEFT:
System.out.println("←"); break;
case RIGHT:
System.out.println("→"); break;
}
}
}
enum Oritation{
UP,DOWN,LEFT,RIGHT;
}
13.权限修饰符
权限 | 描述 |
---|---|
private | 当前类(私家车) |
缺省 | 本类+同包 |
protected | 本类+同包+其他包的子类 |
public | 公交车 |
14.多态
14.1多态的概述
* 面向对象的三大特征:封装,继承,多态
*
* 多态的形式:
* 父类类型 对象名称 = new 子类构造器;
* 接口 对象名称 = new 实现类构造器
*
* 父类类型的范围 > 子类类型范围 animal > cat, 合理性
*
* 多态的概念:
* 同一个类型的对象,执行同一个行为,在不同的状态下会表现出不同的行为特征
* (方法才会有)变量没有多态 <<她喜欢>>
*
* 多态的识别技巧:
* 对于方法调用,编译看左边,运行看右边
* 对于变量的调用,编译看左边,运行也看左边
*
* 多态使用的前提:
* 1. 必须存在继承和存在关系
* 2. 必须存在父类类型的变量引用子类类型的对象
* 3. 需要存在方法重写,才会出现编译看左边,运行看右边
*
* 小结:
* 记住多带的形式,识别,语法即可
public class PolymorphicDemo {
public static void main(String[] args) {
Animal cat = new Cat();
cat.run();
System.out.println(cat.name); // Animal
Animal dog = new Dog();
dog.run();
System.out.println(dog.name); // Animal
}
}
class Cat extends Animal{
public String name = "Cat";
@Override
public void run() { System.out.println("猫跑得飞快"); }
}
class Dog extends Animal{
public String name = "Dog";
@Override
public void run() { System.out.println("狗跑得飞快"); }
}
class Animal{
public String name = "Animal";
public void run(){ System.out.println("动物跑"); }
}
14.2多态的优劣势
* 优势:
* 1.在多态的形势下,右边对象可以实现组件化切换,业务功能也随之改变,便于维护和拓展
* 可以实现类与类之间的解耦
* 2.在实际开发中,父类类型作为方法形式参数,传递子类对象给方法
* 可以传入一切子类对象进行方法的调用,更能体现出多态的扩展性和遍历
*
* 劣势:
* 1.多态情况下,不能直接调用子类特有的功能,编译看左边!!左边
* 父类中没有子类独有的功能,所以代码在编译阶段就直接报错了!!
public class PolymorphicDemo {
public static void main(String[] args) {
go(new Cat());
go(new Dog());
//cat.lookDoor(); 报错了,多态情况下,编译看左边,左边没有独有功能
}
// 开发一个游戏,不同动物开始比赛
public static void go(Animal animal){
System.out.println("开始比赛");
animal.run();
System.out.println("比赛结束");
}
}
class Cat extends Animal {
public String name = "Cat";
@Override
public void run() { System.out.println("猫跑得飞快");}
//子类独有功能
public void catCatchMouse(){ System.out.println("猫抓老鼠"); }
}
class Dog extends Animal {
public String name = "Dog";
@Override
public void run() { System.out.println("狗跑得飞快");}
//子类独有功能
public void lookDoor(){ System.out.println("狗看门"); }
}
class Animal{
public String name = "Animal";
public void run(){ System.out.println("动物跑"); }
14.3引用类型自动转换
* 目标:引用数据类型的自动转换
* 在基础班学过了基本数据类型的转换
* 1.小范围类型的变量或者值可以直接赋值给大范围类型的变量
* 2.大范围类型的变量或者值必须强制转换为小范围类型的变量
*
* 引用数据类型转换的思想是一样的
* 父类类型的范围 > 子类类型的范围
* 引用数据类型的自动类型转换语法:
* 1.子类类型的对象或者变量可以自动类型转换赋值给父类类型的变量
* (其实就是覆盖父类Animal类型,子类都转换为Aniaml类型)
*
* 小结:引用类型的自动类型转换并不能解决多态的劣势
public class PolymorphicDemo {
public static void main(String[] args) {
// 第一种方式
Animal cat = new Cat();
// 第二种方式, 与第一种类似
Cat cat1 = new Cat();
Animal animal = cat1;
}
}
class Animal{
}
class Cat extends Animal{
}
14.4引用类型强制类型转换
* 目标:引用类型强制类型转换
*
* 语法:
* 1.父类类型的变量或者对象必须强制类型转换成子类类型的变量,否则报错!
*
* 前十中类型转换格式:
* 类型 变量名称 = (类型)(对象或者变量)
*
* 注意:有继承/实现关系的两个类型就可以进行强制类型转换,编译阶段一定不报错!
* Java建议在进行强制类型转换之前先判断类型的真是类型,再强制类型转换
* 变量 instanceof 类型: 判断前面的变量是否是后面的类型或者其子类类型
public class PolymorphicDemo {
public static void main(String[] args) {
Animal animal = new Wolf();
animal.run();
if(animal instanceof Wolf){
Wolf wolf = (Wolf) animal;
wolf.catchSheep();
}else if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
Wolf wolf = (Wolf) animal; // 小范围转为大范围
wolf.catchSheep(); // 狼可以抓羊了
// 多态下 类型转换异常
Animal cat = new Cat();
Wolf wolf1 = (Wolf) cat; //运行时 ClassCastException 类型转换异常
wolf.catchSheep();
}
}
class Wolf extends Animal{
@Override
public void run() { System.out.println("dog run"); }
public void catchSheep(){ System.out.println("dog catch sheep"); }
}
class Cat extends Animal{
@Override
public void run() { System.out.println("cat run"); }
public void catchMouse(){ System.out.println("cat catch Mouse"); }
}
class Animal{
public void run(){ System.out.println("Animal run"); }
}
14.5多态接口综合案例
* 设计一个电脑对象,可以接入2个USB设备
* 鼠标,键盘:实现接入,拔出功能
*
* 分析:
* 1.提供2个USB设备,USB设备必须满足,接入和拔出的功能
* 2.开始定义2个实例的实现类代表鼠标和键盘
* 3.定义一个电脑类
public class Demo {
public static void main(String[] args) {
Computer computer = new Computer();
computer.installUSB(new Mouse("雷蛇鼠标"));
computer.installUSB(new KeyBoard("HHKB键盘"));
}
}
class Computer{
// 提供一个安装USB设备的入口
public void installUSB(USB usb){
usb.connect();
if(usb instanceof Mouse){
Mouse mouse = (Mouse)usb;
mouse.doubleClick();
}else if (usb instanceof KeyBoard){
KeyBoard keyBoard = (KeyBoard) usb;
keyBoard.keyDown();
}
}
}
// 定义两个USB设备,鼠标,键盘
class Mouse implements USB{
private String name; //商标
public Mouse(String name){ this.name = name; }
//双击(特有)
public void doubleClick(){ System.out.println(name + "双击了,老铁6666"); }
@Override
public void connect() { System.out.println(name+"成功接入设备"); }
@Override
public void unConnect() { System.out.println(name+"成功拔出设备"); }
}
class KeyBoard implements USB{
private String name; //商标
public KeyBoard(String name){ this.name = name; }
// 敲击键盘(特有)
public void keyDown(){ System.out.println(name + "敲击了键盘,来了老弟"); }
@Override
public void connect() { System.out.println(name+"成功接入设备"); }
@Override
public void unConnect() { System.out.println(name+"成功拔出设备"); }
}
// 完成接入和拔出的功能
interface USB{
void connect();
void unConnect();
}
15.内部类
15.1内部类概述
* 定义:定义在类里面的类就是内部类
* 作用:
* 可以提供更好的封装性
* 内部类有更多的权限修饰符
* 封装性有更多的控制
* 可以体现出组件的思想
*
* 内部类的分类:
* 1.静态内部类
* 2.实例内部类(成员内部类)
* 3.局部内部类
* 4.匿名内部类(重点)
public class InnerClass { // 外部类 不能用 private protected修饰
private class Animal{ // private protected public 缺省 都可以
private String name;
}
}
15.2静态内部类
* 目标: 静态内部类,(了解语法即可)
* 定义: 有static修饰,属于外部类本身,只加载一次
*
* 静态内部类中的成分研究:
* 类有的成分它都有,静态内部类属于外部类本身,只会加载一次
* 所以他的特点和外部类是完全一样的,只是位置在别人里面而已
*
* 外部类 = 宿主 内部类 = 寄生
*
* 静态内部类创建对象的格式:
* 外部类名称.内部类名称 对象名称 = new 外部类名称.内部类构造器
*
* 静态内部类的访问拓展:
* 静态内部类是否可以直接可以访问外部类的静态成员?
* 可以!都输入外部类的静态属性
* 静态内部类是否可以直接访问外部类的实例成员
* 不可以!必须用外部类实例对象访问 实例成员变量
*
public class InnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner("zhangsan",11);
inner.sayHello();
}
}
// 汽车类-发动机类
class Outer{
public static String outerName = "123";
public double salary = 3000;
// 属于外部类本身,只会加载一次
public static class Inner{
public static String schoolName = "黑马";
private String name;
private int age;
public Inner(String name,int age){
this.name = name;
this.age = age;
}
public void sayHello(){
System.out.println(name + " say hello ");
System.out.println(outerName); // 访问外部类静态成员
// System.out.println(salary); 不能直接访问实例成员
}
}
}
15.3实例内部类
* 目标: 成员内部类(了解语法即可)
* 定义:无static修饰的内部类,属于外部类的每个对象的,跟着对象一起加载的
*
* 实例内部类的成分特点:
* 实例内部类中不能定义静态成员,其他都可以定义
* 可以定义常量
*
* 创建对象格式:
* 外部类名称.内部类名称 对象名称 = new 外部类构造器.new 内部类构造器
*
*
* 拓展:
* 1.实例内部类中(写代码的地方)是否可以直接访问内外部类的静态成员?
* 可以,外部类的静态成员可以被 共享访问!
* 2.实例内部类中是否可以访问外部类实例成员?
* 可以,实例内部类属于外部类对象,可以直接访问当前外部类对象的实例成
*
* 小结:
* 实例内部类可以访问外部类的全部成员!
*/
public class InnerClass {
public static void main(String[] args) {
//先有外部类对象,才有内部类对象
//外部类对象是宿主
Outer.Inner inner = new Outer().new Inner();
}
}
// 人类 - 眼睛类
class Outer{
public static int age = 1;
private double salary;
// 当做 Outer的一个成员函数
// 实例内部类: 无static修饰,属于外部类的对象
public class Inner{
//不能再实例内部类中定义静态成员
//public static String schoolName = "黑马"; 报错!
public static final String schoolName = "黑马"; //final可以,常量池
private String name;
public void show(){
System.out.println(age);
System.out.println(salary);
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
15.4局部内部类
* 目标:局部内部类(几乎不用)
*
* 定义在方法中,在构造器中,代码块中,for循环中定义的内部类 就是局部内部类
*
* 局部内部类的成分特点:
* 只能定义实例成员,不能定义静态成员
* 可以定义常量!
*
* 小结:
* 局部内部类没啥用
public class InnerClass {
static{
abstract class A{
}
}
public static void main(String[] args) {
class A{
private String name;
public void test(){
}
}
A a = new A();
a.test(); //装B,过分了
}
public static void test(){
class Animal{
}
class Cat extends Animal{
}
}
}
15.5匿名内部类
* 什么是匿名内部类?
* 就是一个没有名字的局部内部类
* 匿名内部类可以简化代码,也是开发中常用的形式
* 匿名内部类的格式:
* new 类名|抽象类|接口(形参){
* 方法重写
* }
*
* 匿名内部类的特点:
* 1.匿名内部类是一个没有名字的内部类
* 2.匿名内部类一旦写出来,就会立即创建一个【匿名内部类的对象】返回
* 3.匿名内部类的对象的类型相当于是当前new的那个类型的子类类型
编译时 外部类名$1.class
public class InnerClass {
public static void main(String[] args) {
// new Animal()不能使用,加个{}就可以成为实例类,也是对象
Animal animal = new Animal() { //只使用一次,干掉子类猫
@Override
public void run() {
System.out.println("猫跑的贼溜");
}
};
animal.run();
animal.go();
}
}
//class Cat extends Animal{
// @Override
// public void run() {
// System.out.println("猫跑的贼溜");
// }
//}
abstract class Animal{
public abstract void run();
public void go(){
System.out.println("开始go");
}
}
15.6匿名内部类案例
* 目标: 匿名内部类的使用形式(关注语法即可)
* 需求:很多角色要一起参加游泳比赛(老师,学生,运动员)
public class InnerClass {
public static void main(String[] args) {
Swim teacher = new Swim() {
@Override
public void swimming() {
System.out.println("teacher swimming!");
}
};
go(teacher);
go(new Swim() {
@Override
public void swimming() {
System.out.println("student swimming!");
}
});
}
// 提供一个方法 让 全部角色进入比赛
public static void go(Swim swim){
System.out.println("开始......");
swim.swimming();
System.out.println("结束......");
}
}
interface Swim{
void swimming();
}
案例二
public class InnerClass02 {
public static void main(String[] args) {
JFrame my_frame = new JFrame("my frame");
my_frame.setSize(400,300);
my_frame.setLocationRelativeTo(null); // 窗口居中
// 添加按钮
JButton button = new JButton("开始登录");
JPanel jPanel = new JPanel();
jPanel.add(button);
my_frame.add(jPanel);
//按钮监听事
button.addActionListener(new ActionListener() { // 匿名内部咧
@Override
public void actionPerformed(ActionEvent actionEvent) {
System.out.println("用户点击了,触发登录~~");
}
});
// 简化 lambda表达式, 只有一个接口,只有一个方法
button.addActionListener( s -> System.out.println("用户点击了!"));
my_frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //关闭时退出程序
my_frame.setVisible(true);
}
}
16.包以及权限修饰符
相同包下的类可以直接访问
不同包下的类必须先导包才可以访问!
* private 缺省 protected public(公交车)
* 本类中 √ √ √ √
* 本包下其他类中 √ √ √
* 其他包下的子类中 √ √
* 其他包下的类中 √
*