当前位置: 移动技术网 > IT编程>软件设计>面向对象 > 07:面向对象【4】

07:面向对象【4】

2020年07月31日  | 移动技术网IT编程  | 我要评论
一:抽象类和接口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 接口。

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

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 "


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类常用的方法

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
 */


三:内部类

3.1 内部类

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

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中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、 局部内部类。

非静态内部类

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

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

内部类的访问:

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

静态内部类

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
 */

匿名内部类

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();
}

注意

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

局部内部类

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

 

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网