【java】前八章:快速回忆(二)

简介: 【java】前八章:快速回忆

第五章:类与类的继承(应该是非常重要的一章)


面向对象的基本概念


面向对象: 把涉及到的对象抽离出来,然后考虑对象之间的关系构建整个项目,面向对象的设计是一种提供符号设计系统的面向对象的实现过程。面向对象是以领域对象开发为指导。

举例说明(可能不太正确):

把大象装进冰箱


面向过程的思维:

  • 打开冰箱
  • 装进大象
  • 关闭冰箱


面向对象的思想:

  • 冰箱打开
  • 冰箱存储
  • 冰箱关闭

2f6b87c5df187dce5f78233b5cba233b_5482901b568a543337619b176b150a0f.png下面,我们从对象,开始了解上图所有内容,


1.对象的定义


含义


对象是类的实例,拥有具体的状态行为。例如Student是类(描述同类对象共同的状态和行为),而对象是指一个具体的Student个体,对象是动态的,每个对象都拥有一个从创建,运行到消亡的动态过程。同时对象也同样占内存空间,存储对象的状态数据,即成员变量。(比如文海同学<对象>的身高<成员变量>)

    //定义方法:类名 对象名;
    //或者类名 对象名 = new 类名( 参数列表 );
    Student a;
    Student a = new Student();

组成.


和类中成员变量以及方法有关(好比一个人,有多种属性:姓名、性别、年龄、体重等,都有多种行为:吃饭、走路等)对象=属性+行为


模板

.

没啥好说的,模板就是类,那么介绍一下类

什么是类:类不是一个实体的存在,比如手机这个类,手机并不是实体,如iPhone7 才是一个实体,手机并不是,类只是一个模子,确定对象将会有的特征(属性)和行为(方法)

类的组成: 属性和方法(如果你是从上看到这,就不会有对此处的疑问)

类的定义方法:

    定义类名 public class 类名{
    //[初始化模块](https://www.cnblogs.com/wp456/p/3233186.html "初始化模块")的定义【初始化模块首先被执行】
     //定义属性(成员变量)的部分
      编写类的属性 属性1的类型 属性1;
      属性2的类型 属性2;
      ..........
      属性n的类型 属性n;
    //定义方法(行为)的部分;
      编写类的方法 方法1;
      方法2;
       ........
      方法n;
    }

例如:手机类的定义:

点击查看代码

public class Telphone {//1.定义一个类
    //2.定义属性(成员变量)
    float screen;//屏幕
    float cpu;//cpu大小
    float mem;//内存大小
    //3.定义方法
void call(){
    System.out.println("Telphone有打电话的功能!");
}
void sendMessage(){
   System.out.println("screen:"+ screen + "cpu:"+ cpu + "mem:"+ mem +"Telphone有发短信的功能");
}
}

成员变量与局部变量的区别和c差不多,就不过多赘述了,但是修饰符需要重点掌握

754feb0af2055c13bec076e50127c91a_9c741298f453458f4ae4990b0b112860.png

56af6a6b7cc39fd06e5dc9cd44e94aaf_51d05b2a8447bf189e2e4f696f5f13a0.png


特点


  • 封装:封装是一种信息屏蔽技术,通过封装讲对象的状态和行为结合成一个独立的模块,尽可能隐藏对象的内部细节(包括对象内部的私有状态以及行为的具体实现)。封装的目的在于把对象的设计者和使用者分开,作为使用者不需要了解对象内部的实现细节,只需要使用设计者提供的行为方法实现功能即可。

private 关键字

是一个权限修饰符。

用于修饰成员(成员变量和成员函数)

被私有化的成员只在本类中有效。


常用之一:

将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性。


private :私有,是一个权限修饰符。用于修饰成员。

私有的内容只在本类中有效。

注意: 私有仅仅是封装的一种体现。


  • 继承:继承表示类之间的层次关系。继承关系使得子类的对象可以共享父类对象的状态(属性<非私有成员变量>)和行为(方法<除构造方法外>)

例如:

父类:Telphone

点击查看代码

package HOME9;
public class Telphone {
      //2.定义属性(成员变量)
      float screen;//屏幕
     private float cpu;//cpu大小
      float mem;//内存大小
      //3.定义方法
  void call(){
      System.out.println("Telphone有打电话的功能!");
  }
  void sendMessage(){
     System.out.println("screen:"+ screen + "cpu:"+ cpu + "mem:"+ mem +"Telphone有发短信的功能");
  }
}


子类:iPhone 点击查看代码

package HOME9;
public class iPhone extends Telphone {
}

测试:

public static void main(String[] args) {
    iPhone apple = new iPhone();
    //子类可以继承父类非private属性(成员变量)和方法(非构造方法)
    //apple.cpu =5;如果有此行,则报错‘The field Telphone.cpu is not visible’
    apple.mem = 6;
    apple.screen = 7;
    apple.call();
    apple.sendMessage();
  }

结果:

58f000c61ebf0b36ccc4c8a2f0ed3270_e7191dd2f55bc15eb5ef113250d106e5.png

多态:多态性是指同名的行为方法可在不同类中具有不同的实现。在子类继承父类的同时,类的方法实现可以进行扩充或者修改,使子类的同名方法更适合子类的对象


多态的实现的必要条件:(重点要记下)

  • 存在继承关系
  • 存在方法重写
  • 父类引用指向子类对象


多态的优点:

  • 简化了代码
  • 提高了维护性和扩展性


例如:

点击查看代码

public class DuoTaiDemo01 {
  public static void main(String[] args) {
    Man m = new Doctor();
    m.cut();
    m = new Director();
    m.cut();
    m = new Hairdresser();
    m.cut();
  }
}
class Man {
  public void cut() {
    System.out.println("我是man, 我也不知道怎么cut");
  }
}
class Doctor extends Man {
  public void cut() {
    System.out.println("动手术");
  }
}
class Director extends Man {
  @Override
  public void cut() {
    System.out.println("暂停");
  }
}
class Hairdresser extends Man {
  @Override
  public void cut() {
    System.out.println("剪头发");
  }
}


重点来了,拿笔记下


多态访问成员的特点:


Father father = new Son()

左边类型 ————右边类型


成员变量:

  1. 编译时期看左边的类型,如果左边类型中没有变量,编译报错
  2. 运行时期看左边类型,左边类型的变量的值就是运行的结果
  3. 编译看左边,执行看左边


成员方法:

编译看左边,执行看右边

构造方法:

1.多态访问子类构造方法会先访问父类构造方法

2.帮助子类初始化父类继承过来的成员

静态方法:

编译看左边,执行看左边

举例代码如下:

package HOME9;
public class DuoTaiDemo02 {
  public static void main(String[] args) {
    Fu fu = new Zi();
    System.out.println(fu.num); // 10
    fu.method();
    fu.show();
  }
}
class Fu {
  int num = 10;
  public void method() {
    System.out.println("Fu.method()");
  }
  public static void show() {
    System.out.println("Fu.show");
  }
}
class Zi extends Fu {
  int num = 20;
  @Override
  public void method() {
    System.out.println("Zi.method()");
  }
  public static void show() {
    System.out.println("Zi.show");
  }
}

结果:

fce856262eb8e9eb3016a565a8fd7314_7a48658303c2492f71253564284a125d.png


向上转型(自动转换)

格式:<父类型> <引用变量名> = new <子类型>();

特点:

子类转为父类 父类的引用指向子类对象。可以理解为自动进行类型转换(和自动类型转换完全是两个概念)

此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法

此时通过父类引用变量无法调用子类特有的属性和方法

解决方法(instanceof + 向下转型)


向下转型(强制转换)

格式:<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;

特点:

父类转为子类,父类引用转为子类对象。可以理解为强制类型转换

在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常


异常名称: 类型转换异常 java.lang.ClassCastException

产生原因: 在向下转型的过程中,没有转换成真实的类型

解决办法: 在每次向下转型之前做一个类型的判断


类型判断的语法: instanceof

左边对象 instanceof 类名 这个表达式的结果是boolean类型

测试它左边的对象是否是它右边的类的实例


多态的弊端可以使用instanceof关键字+向下转型来解决

我们知道我们需要对父类的所有子类做逐一判断,违背了开闭原则

为了开闭原则我们还是可以继续开发,但是如果这个父类引用是Object呢?

无法做逐一个判断,安全隐患一致存在,可以考虑是泛型。举例1代码如下所示:

package HOME9;
public class DuoTaiDemo02 {
  public static void main(String[] args) {
    Car c = new Benz();
    c.run();
    c = new BYD();
    c.run();
    if (c instanceof Benz) {
      Benz benz = (Benz) c;
      benz.leakOli();
    } else if (c instanceof BMW) {
      BMW b = (BMW) c;
      b.fillOil();
    } else  if (c instanceof BYD) {
      BYD byd = (BYD) c;
      byd.electric();
    }
    Object obj = new BMW();
  }
}
class Car {
  public void run() {
    System.out.println("Car.run()");
  }
}
class BMW extends Car {
  @Override
  public void run() {
    System.out.println("BMW.run()");
  }
  public void fillOil() {
    System.out.println("加油");
  }
}
class Benz extends Car {
  @Override
  public void run() {
    System.out.println("Benz.run()");
  }
  public void leakOli() {
    System.out.println("漏油");
  }
}
class BYD extends Car {
  @Override
  public void run() {
    System.out.println("BYD.run()");
  }、*------*、
  public void electric() {
    System.out.println("充电");
  }
}


结果:

bd7d360220be01b57fc30a7c8017ed7b_f7629fb3d37277e006f1335383725e0e.png


第六章:多态与内部类


多态(第五章写的有点多了,这章就不写了):


主要内容(向上转型,向下转型,instanceof运算符)


抽象类和抽象方法


抽象类:是对具体类的抽象,用来完成类框架的共享的公共设计,具体子类继承并扩展公共设计(自认为像多态),

抽象类不能实例化对象


一、抽象(abstract)的使用

当父类的某些方法不确定时,可以用abstract关键字来修饰该方法[抽象方法],用abstract来修饰该类[抽象类]。

我们都知道,我们都知道,父类是将子类所共同拥有的属性和方法进行抽取,这些属性和方法中,有的是已经明确实现了的,有的还无法确定,那么我们就可以将其定义成抽象,在后日子类进行重用,进行具体化。这样,抽象类也就诞生了。


例如,定义了“动物”父类,其中“动物名称”和“动物年龄”属性已经明确了,但是“动物叫”的方法没有明确,此时就可以将“动物叫”定义为抽象方法。

所以,抽象类是为了把相同的但不确定的东西的提取出来,为了以后的重用。定义成抽象类的目的,就是为了在子类中实现抽象类

例子:

package javastudy;
public class AbstractDemo1 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    }
}
// 这就是一个抽象类
abstract class Animal {
    String name;
    int age;
    // 动物会叫
    public abstract void cry(); // 不确定动物怎么叫的。定义成抽象方法,来解决父类方法的不确定性。抽象方法在父类中不能实现,所以没有函数体。但在后续在继承时,要具体实现此方法。
}
// 抽象类可以被继承
// 当继承的父类是抽象类时,需要将抽象类中的所有抽象方法全部实现。
class cat extends Animal {
    // 实现父类的cry抽象方法
    public void cry() {
        System.out.println("猫叫:");
    }
}


接口


接口与抽象类似,是对类的一种抽象,指明了类所具备的功能,接口描述的是一种能力。例如组织一次会议有接待参与人员的需求。


接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。


除非实现接口的类是抽象类,否则该类要定义接口中的所有方法


接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。


接口与类的区别和接口的特性

点这->Java 接口我没看明白

课本上的解释:抽象类更主要的是体现了类模板的设计思想,定义其子类的通用特性及部分已近实现的共有功能。抽象类与子类实现了“一般到特殊”之间的关系(多态是不是一种方法,而抽象类就是实现此方法的手段,包括接口也是??


接口中的默认方法(default)


public interface MyInterface {
    // 普通接口方法
    default void defaultMethod() {
        // 默认方法
    }
}


为什么需要默认方法


在Java8之前,接口只能有抽象方法。如果不强制所有实现类创建新方法的实现,就不能向现有接口添加新功能。


Java8新增默认方法的原因非常明显。


在一个典型的基于抽象的设计中,一个接口有一个或多个实现类。接口要新增方法,所有的实现都要新增这个方法的实现。否则就不满足接口的约束。


默认接口方法是处理此问题的解决方案。在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。

例如:

点击查看代码

interface MobilePhone {
    /**
     * 获取手机品牌
     */
    String getBrand();
    /**
     * 获取手机颜色
     */
    String getColor();
    /**
     * 获取手机长度(毫米)
     */
    Double getLength();
    /**
     * 设置手机时间
     */
    default String setTime(String newTime) {
        return "time set to " + newTime;
    }
    /**
     * 对getLength方法进行拓展,返回厘米为单位的长度
     */
    default String getLengthInCm() {
        return getLength() / 10 + "cm";
    }
}

点击查看代码

public class DefaultTests implements MobilePhone {
    @Override
    public String getBrand() {
        return "iphone";
    }
    @Override
    public String getColor() {
        return "red";
    }
    @Override
    public Double getLength() {
        return 150.00;
    }
    @Test
    public void defaultTest() {
        System.out.println(setTime("8:00 am"));
        System.out.println(getLengthInCm());
    }
}

结果:

efff61c63c7ac5f8c2f683342e746219_06af01f4adae4f46c487a799cc819395.png


接口中的静态方法


接口中的静态方法和类中定义的静态方法一样,不属于特定对象,所以它们不是实现接口的api的一部分,必须使用InterfaceName.staticMethod来调用它们。


为了理解静态方法如何在接口中工作,让我们看一个实例:

interface NewInterface { 
    // 静态方法
    static void hello() 
    { 
        System.out.println("Hello, New Static Method Here"); 
    } 
    // 抽象方法 
    void overrideMethod(String str); 
} 
// 实现类
public class InterfaceDemo implements NewInterface { 
    public static void main(String[] args) 
    { 
        InterfaceDemo interfaceDemo = new InterfaceDemo(); 
        // 调用接口静态方法 
        NewInterface.hello(); 
        // 调用被覆写后抽象方法 
        interfaceDemo.overrideMethod("Hello, Override Method here"); 
    } 
    // 实现接口方法
    @Override
    public void overrideMethod(String str) 
    { 
        System.out.println(str); 
  }


为什么接口要支持静态方法


接口中的静态方法背后的思想是提供一种简单的机制,允许通过将相关的方法内聚在接口中,而不必创建新的对象。


抽象类也可以做同样的事情。主要的区别在于抽象类可以有构造函数、成员变量和方法。


推荐把和只和接口相关的静态utility方法放在接口中(提高内聚性),而不需要额外创建一些utility类专门去放置这些方法。


内部类


Java 一个类中可以嵌套另外一个类,语法格式如下:

class OuterClass {   // 外部类
    // ...
    class NestedClass { // 嵌套类,或称为内部类
        // ...
    }
}

要访问内部类,可以通过创建外部类的对象,然后创建内部类的对象来实现。

嵌套类有两种类型:

  • 非静态内部类
  • 静态内部类


非静态内部类


非静态内部类是一个类中嵌套着另外一个类。 它有访问外部类成员的权限, 通常被称为内部类。

由于内部类嵌套在外部类中,因此必须首先实例化外部类,然后创建内部类的对象来实现。

实例:

点击查看代码

class OuterClass {
  int x = 10;
  class InnerClass {
    int y = 5;
  }
}
public class MyMainClass {
  public static void main(String[] args) {
    OuterClass myOuter = new OuterClass();
    OuterClass.InnerClass myInner = myOuter.new InnerClass();
    System.out.println(myInner.y + myOuter.x);
  }
}

以上实例执行输出结果为:

e688b2a56552664af670da6512de7e9f_bd876e79e16b3902ca7bbbc89e5184a8.png

私有的内部类

内部类可以使用 private 或 protected 来修饰,如果你不希望内部类被外部类访问可以使用 private 修饰符:

实例:

点击查看代码

class OuterClass {
  int x = 10;
  private class InnerClass {
    int y = 5;
  }
}
public class MyMainClass {
  public static void main(String[] args) {
    OuterClass myOuter = new OuterClass();
    OuterClass.InnerClass myInner = myOuter.new InnerClass();
    System.out.println(myInner.y + myOuter.x);
  }
}

报错:

d076e10e667c7d151e83eff5864a4509_701a33d9eae3565f796764f984c12c7f.png

错误提示信息’The type OuterClass.InnerClass is not visible‘


静态内部类


静态内部类可以使用 static 关键字定义,静态内部类我们不需要创建外部类来访问,可以直接访问它:

实例:

点击查看代码

class OuterClass {
  int x = 10;
  static class InnerClass {
    int y = 5;
  }
}
public class MyMainClass {
  public static void main(String[] args) {
    OuterClass.InnerClass myInner = new OuterClass.InnerClass();
    System.out.println(myInner.y);
  }
}

以上实例执行输出结果为:

64a862fe5069bb2cb0782a54c19eaf70_e31999e29f93c8c50af8cd8ae238524b.png

eea9193aecf0b2181066b1cbcdc36086_5c7095a1f90a041fb51bbc8f3196b5b9.png

好像还有一个匿名内部类,看不懂


相关文章
|
5月前
|
Java 开发者
那些年,我们追过的Java多态——回忆篇
【6月更文挑战第17天】重温Java多态,它激发了初学者对面向对象编程的热情。多态展示了代码的灵活性和可扩展性,通过抽象和接口使设计更高效。在实践中,如GUI事件处理和游戏开发,多态广泛应用。随着时间的推移,理解加深,多态被视为反映现实多样性的编程哲学。对初学者,它是探索编程世界的钥匙,不应惧怕困惑,应多实践,享受与计算机对话的乐趣。多态,是编程旅程中宝贵的财富和成长见证。
29 0
|
Java
【java】前八章:快速回忆(三)
【java】前八章:快速回忆
93 0
|
存储 Java 测试技术
【java】前八章:快速回忆(一)
【java】前八章:快速回忆
109 0
|
Java Windows
Java 将照片转化为回忆中的照片,琉璃般的岁月 | Java工具类
Java 将照片转化为回忆中的照片,琉璃般的岁月 | Java工具类
Java 将照片转化为回忆中的照片,琉璃般的岁月 | Java工具类
|
SQL 算法 Java
Java生产填坑经历之全面回忆
屏幕快照 2018-07-30 下午4.01.49.png 生产填坑的经历为什么要称之为全面回忆呢,因为恰巧笔者之前看了一部科幻电影,名字就叫《全面回忆》Total Recall,该片于2012年10月20日在中国上映,豆瓣评分7.0。
1364 0
|
9天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
16天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
7天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
8天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
7天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
下一篇
无影云桌面