欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

07:面向对象【4】

程序员文章站 2022-03-03 10:41:23
一:抽象类和接口1.1 抽象方法和抽象类抽象方法 :使用 abstract 修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。抽象类 :包含抽象方法的类就是抽象类。通过abstract 方法定义规范,然后要求子类必须定义 具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。【示例5-16】抽象类和抽象方法的基本用法package cn.sxt.text;//抽象类abstract class Animal...

目录

一:抽象类和接口

1.1 抽象方法和抽象类

1.2 接口interface

1.2.1 接口的作用

1.2.2 如何定义和使用接口(JDK8以前)

1.2.3 接口中定义静态方法和默认方法(JDK8以后)

1.2.4 接口的多继承

1.2.5 面向接口编程

二:字符串String类详解

2.1 String基础

​2.2 String类和常量池

2.3 String类常用的方法

2.4 字符串相等的判断

​三:内部类

3.1 内部类

3.2 内部类的概念

3.3 内部类的分类


一:抽象类和接口

1.1 抽象方法和抽象类

抽象方法 :使用 abstract 修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。

抽象类 :包含抽象方法的类就是抽象类。通过abstract 方法定义规范,然后要求子类必须定义 具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

【示例5-16】抽象类和抽象方法的基本用法

package cn.sxt.text;

//抽象类
abstract  class Animalx{

    abstract public void shout(); //抽象方法
}

class Dogg extends Animalx{
    //子类必须实现父类的抽象方法,否则编译错误
    public void shout() {
        System.out.println("汪汪汪!!!");
    }
    public void seeDoor(){
        System.out.println("看门中......");
    }
}

public class TestAbstractClass {

    public static void main(String[] args) {
        Dogg a =new Dogg();
        a.shout();
        a.seeDoor();

        Animalx x = new Dogg();
        x.shout();
        //x.seeDoor();  //编译错误,只能用抽象方法的
    }
}

1.2 接口interface

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思 想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须能干掉坏人;如果你是坏人,则必须欺负好人。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计 模式都只针对具备了抽象能力的语言(比如C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。

1.2.1 接口的作用

 为什么需要接口?接口和抽象类的区别? 

接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全 面地专业地实现了:规范和具体实现的分离。

抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。

从接口的实现者角度看,接口定义了可以向外部提供的服务。

从接口的调用者角度看,接口定义了实现者能提供那些服务。

接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。大家在工作以 后,做系统时往往就是使用“面向接口”的思想来设计系统。

接口和实现类不是父子关系,是实现规则的关系。比如:我定义一个接口 Runnable, Car 实现它就能在地上跑,Train实现它也能在地上跑,飞机实现它也能在地上跑。就是说, 如果它是交通工具,就一定能跑,但是一定要实现 Runnable 接口。
07:面向对象【4】

1.2.2 如何定义和使用接口(JDK8以前)

07:面向对象【4】

07:面向对象【4】

package cn.sxt.text;

import org.w3c.dom.ls.LSOutput;

public class TestInterface {
    public static void main(String[] args) {
        Volant volant = new Angel();
        volant.fly();
        System.out.println(volant.FLY_HIGT);

        Honest honest = new GoodMan();
        honest.helpOther();
    }
}

/**飞行接口*/
interface Volant{

    int FLY_HIGT = 100; // 总是:public static final 类型的;
    void fly(); //总是:public abstract void fly();
}
/**善良节接口*/
interface Honest{
    void helpOther();
}


/**Angel 类实现飞行接口和善良接口*/
class Angel implements Volant,Honest{

    public void fly(){
        System.out.println("我是天使,飞起来啦!");
    }

    public void helpOther(){
        System.out.println("扶老奶奶过马路!");
    }
}

class GoodMan implements Honest{

    public void helpOther(){
        System.out.println("扶老奶奶过马路!");
    }
}

class BridMan implements Volant{

    public void  fly(){
        System.out.println("我是鸟人!我在飞!");
    }
}

1.2.3 接口中定义静态方法和默认方法(JDK8以后)

JAVA8之前,接口里的方法要求全部是抽象方法。

JAVA8(含 8)之后,以后允许在接口里定义默认方法和类方法。

1. 默认方法

Java8及以上新版本,允许给接口添加一个非抽象的方法实现,只需要使用 default 关 键字即可,这个特征又叫做默认方法(也称为扩展方法)。
默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供默认方法的实现,所有这个接口的实现类都会通过继承得到这个方法。

本接口的默认方法中可以调用静态方法。

package cn.sxt.text;

public class Test11 {

    public static void main(String[] args) {
        A a =new B();
        a.x();
    }

}
interface A{

    default void x(){
        System.out.println("我是默认方法呀!!!");
    }
}

class B implements A{

    public void x() {
        System.out.println("我不是默认方法呀!!!");
    }
}
/**
 * 我不是默认方法呀!!!
 */

2. 静态方法

JAVA8以后,我们也可以在接口中直接定义静态方法的实现。这个静态方法直接从属 于接口(接口也是类,一种特殊的类),可以通过接口名调用。

如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类。 可以通过子类名直接调用

package cn.sxt.text;

public class Testx {

    public static void main(String[] args) {
        A.staticMethonA();
        B.staticMethonB();
    }
}

interface  A{

    public  static void staticMethonA(){
        System.out.println("我是A中静态方法!");
    }
}

class B implements  A{

    public static void staticMethonB(){
        System.out.println("我是B中的静态方法!");
    }
}
/**
 * 我是A中静态方法!
 * 我是B中的静态方法!
 * */

1.2.4 接口的多继承

接口完全支持多继承。和类的继承类似,子接口扩展某个父接口,将会获得父接口中所 定义的一切。

package cn.sxt.text;

interface A{
    void testa();
}
interface B{
    void testb();
}

/**接口可以多继承:接口 C继承接口 A 和B*/
interface C extends A,B{
    void testc();
}

public class Testx implements C {
    
    public void testa(){}
    public void testb(){}
    public void testc(){}
}

1.2.5 面向接口编程

面向接口编程是面向对象编程的一部分。 为什么需要面向接口编程? 软件设计中最难处理的就是需求的复杂变化,需求的变化更 多的体现在具体实现上。我们的编程如果围绕具体实现来展开就会陷入”复杂变化”的汪洋 大海中,软件也就不能最终实现。我们必须围绕某种稳定的东西开展,才能以静制动,实现 规范的高质量的项目。

接口就是规范,就是项目中最稳定的核心! 面向接口编程可以让我们把握住真正核心 的东西,使实现复杂多变的需求成为可能。

通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高 整个系统的可扩展性和和可维护性。

面向接口编程的概念比接口本身的概念要大得多。设计阶段相对比较困难,在你没有写 实现时就要想好接口,接口一变就乱套了,所以设计要比实现难!

二:字符串String类详解

2.1 String基础

  • String类又称作不可变字符序列。
  • String位于 java.lang 包中,Java程序默认导入 java.lang 包下的所有类。
  • Java字符串就是 Unicode 字符序列,例如字符串“Java”就是4个 Unicode 字 符’J’、’a’、’v’、’a’组成的。
  • Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个预定义的类 String,每个用双引号括起来的字符串都是String 类的一个实例

【示例5-25】String类的简单使用

String e = "" ; // 空字符串
String greeting = " Hello World "

07:面向对象【4】
2.2 String类和常量池

在Java的内存分析中,我们会经常听到关于“常量池”的描述,实际上常量池也分了 以下三种:

1. 全局字符串常量池(String Pool)

全局字符串常量池中存放的内容是在类加载完成后存到StringPool 中的,在每个 VM 中只有一份,存放的是字符串常量的引用值(在堆中生成字符串对象实例)。

2. class 文件常量池(Class Constant Pool)

class 常量池是在编译的时候每个 class 都有的,在编译阶段,存放的是常量(文本字 符串、final 常量等)和符号引用。

3. 运行时常量池(Runtime Constant Pool)

运行时常量池是在类加载完成之后,将每个 class 常量池中的符号引用值转存到运行时 常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换 成直接引用,与全局常量池中的引用值保持一致。

【示例5-28】字符串相等判断(以后一般判断字符串值是否相等,使用equals())

package cn.sxt.text;

public class Testx {

    public static void main(String[] args) {

        String str1 ="abc";
        String str2 = new String("abc");
        String str3 = "abc";
        System.out.println(str1==str3);
        System.out.println(str2==str3);
        System.out.println(str2.equals(str3));
    }
}
/***
 * true
 * false
 * true
 */

2.3 String类常用的方法

07:面向对象【4】

07:面向对象【4】

package com.bjsxt.string;

public class Test1 {
    public static void main(String[] args) {
        String  str1 = new String("abcdefg");
        String  str2 = "abcdefg";
        String  str3 = "abcdEFG";
        String  str4 = "def";

        System.out.println(str1==str2);
        System.out.println(str1);
        System.out.println(str2);
        //设计到字符串比较的时候,都用equals方法
        System.out.println(str1.equals(str2));
        System.out.println(str1.length());      //7

        System.out.println(str2.charAt(0));
        System.out.println(str2.charAt(6));     //str2.length()-1
        System.out.println(str2.charAt(str2.length()-1));       //取字符串的最后一个字符
        System.out.println(str2.equals(str3));      //false
        System.out.println(str2.equalsIgnoreCase(str3));    //true

        //从开头到结尾查找,返回找到的第一个子字符串的索引位置。如未找到,返回-1
        System.out.println("abcdefgdefg".indexOf("def"));       //结果:3
        System.out.println("abcdefgdefg".indexOf("DF"));        //结果:-1
        //从末尾开始查找
        System.out.println("abcdefgdefg".lastIndexOf("def"));       //结果:7

        //字符串的替换
        String  str5 = "abcdbcd".replace('d','D');
        System.out.println(str5);       //abcDbcD
        String  str6 = "abcdbcd".replace("cd","HELLO");
        System.out.println(str6);       //abHELLObHELLO

        System.out.println("sxt,i love u".startsWith("sxt"));   //true
        System.out.println("sxt,i love u".endsWith("sxt"));     //false


        //截取子字符串
        String  str7 = "abcdefghijklmnopqrstuvwxyz".substring(6);
        System.out.println(str7);       //ghijklmnopqrstuvwxyz
        String  str8 = "abcdefghijklmnopqrstuvwxyz".substring(6,11);    //6-(11-1)
        System.out.println(str8);       //ghijk

        System.out.println("abcdE".toUpperCase());
        System.out.println("abcdE".toLowerCase());

        String str9 = "  a b  ";    //长度7
        String str10 = str9.trim();
        System.out.println(str10.length());
        System.out.println(str10);

        //String是不可变字符序列。所有的替换、截取子字符串、去空格、转换大小写等都是生成了新字符串
        System.out.println(str9.replace(" ",""));
        System.out.println(str9);
    }
}

2.4 字符串相等的判断

  • equals 方法用来检测两个字符串内容是否相等。如果字符串 s 和 t 内容相等,则 s.equals(t)返回 true,否则返回 false。
  • 要测试两个字符串除了大小写区别外是否是相等的,需要使用equalsIgnoreCase 方法。
  • 判断字符串是否相等不要使用"=="。

【示例5-32】字符串的比较:"= ="与equals()方法

package cn.sxt.text;

import org.w3c.dom.ls.LSOutput;

public class name {

    public static void main(String[] args) {
        String g1 ="sshyes";
        String g2 ="sshyes";
        String g3 =new String("sshyes");
        System.out.println(g1==g2);
        System.out.println(g1==g3);
        System.out.println(g1.equals(g3));
    }
}
/**
 * true
 * false
 * true
 */

07:面向对象【4】
三:内部类

3.1 内部类

内部类是一类特殊的类,指的是定义在一个类的内部的类。实际开发中,为了方便的使 用外部类的相关属性和方法,这时候我们通常会定义一个内部类。

07:面向对象【4】

3.2 内部类的概念

一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内 部定义,称为内部类(innerclasses)。 内部类可以使用 public、default、protected 、private 以及 static 修饰。而外部顶 级类(我们以前接触的类)只能使用 public和default 修饰。 

注意 内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名 为 Outer 的外部类和其内部定义的名为 Inner 的内部类。编译完成后会出现 Outer.class 和 Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法 名可以和外部类的相同。

package mycode;


import org.w3c.dom.ls.LSOutput;

/**外部类Outer*/
public class Outer {

    private  int age =10;
    public void show(){
        System.out.println(age);
    }

    /**外部类*/
    public class Inner{
        //内部类中可以声明与外部类同名的属性与方法
        private  int age = 20;
        public void show(){
            System.out.println(age); 
            /**访问外部类的变量*/
            System.out.println(Outer.this.age);
        } 
    }

    public static void main(String[] args) {

        Outer.Inner o =new Outer().new Inner();
        System.out.println(o.age);
        o.show();
    }
}
/**
 * 20
 * 20
 * 10
 */

内部类的作用:

  • 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。 
  • 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类 不能访问内部类的内部属性。

3.3 内部类的分类

在Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、 局部内部类。

07:面向对象【4】

非静态内部类

非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)

  • 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类 对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对 象。
  • 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类 成员。
  • 非静态内部类不能有静态方法、静态属性和静态初始化块。
  • 成员变量访问要点:
  1. 内部类里方法的局部变量:变量名。
  2.  内部类属性:this.变量名。
  3. 外部类属性:外部类名.this.变量名

07:面向对象【4】

内部类的访问:

1. 外部类中定义内部类:new Inner()。 2. 外部类以外的地方使用非静态内部类: Outer.Inner varname = new Outer().new Inner()。

静态内部类

07:面向对象【4】

package mycode;

/*
测试静态内部类
 */
public class Outer2 {
    private int a =10;
    private  static int b= 20;
    //相当于外部类的一个静态成员
    static class Inner2{
        public void test(){
            //System.out.println(a);// 静 态 内 部 类 不 能 访 问 外 部 类 的 普
            //通 属 性
            System.out.println(b);
        }
    }
}

class Outerx{
    public static void main(String[] args) {
        
        Outer2.Inner2 inner =new Outer2.Inner2();
        inner.test();
    }
}
/**
 * 20
 */

匿名内部类

07:面向对象【4】

package mycode;

public class Testx {

    public void test1(A a){
        a.run();
    }

    public static void main(String[] args) {
        Testx t =new Testx();
        t.test1(new A() {
            @Override
            public void run() {
                System.out.println("第一个内部类");
            }
        });
    }
}

interface A{
    void run();
}

注意

  • 匿名内部类没有访问修饰符。
  • 匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。

局部内部类

定义在方法内部的,作用域只限于本方法,称为局部内部类。
局部内部类的的使用主要是用来解决比较复杂的问题,想创建一个类来辅助我们的解决 方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员 内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就 会失效。
局部内部类在实际开发中应用很少。

07:面向对象【4】 

本文地址:https://blog.csdn.net/weixin_44359595/article/details/107666515

相关标签: JAVA