ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java学习之路之week4day2

2022-01-26 16:34:21  阅读:129  来源: 互联网

标签:Java 内部 对象 之路 接口 访问 week4day2 方法 public


向Java程序员的目标前进!

day16

面向对象—续6

学习内容

接口—续

形式参数问题

方法的形式参数传递基本数据类型或引用数据类型。形式参数是基本数据类型的话,实际参数就是当前对应的数据值,而且形参的改变不会影响实际参数,比较简单。形式参数是引用数据类型的话,实际参数就是当前对应的空间地址值。

方法的形式参数是引用数据类型时的分析:

  • (如果引用数据类型是)具体类:实际参数应该创建当前具体类对象
  • 抽象类:实际参数需要传递应该创建当前抽象类的子类对象(抽象类多态)
  • 接口:先定义接口的子实现类,然后实际参数中传递子实现类的匿名对象。(接口多态)
  • 数组:实际参数需要传递数组对象

如今我们终于可以将week1的那张数据类型图补充完整了

在这里插入图片描述

练习:接口作为形式参数的猫狗案例

/**
 * 设计一个Java程序
 * (1)定义一个接口CanCry,描述会吼叫的方法public void cry()
 * (2)分别定义狗类(Dog)和猫类(Cat),实现CanCry接口。实现方法的功能分别为:
 *  打印输出“我是狗,我的叫声是汪汪汪”、“我是猫,我的叫声是喵喵喵”
 * (3)定义一个主类G,
 * 	定义一个void  makeCry(CanCry c)方法,其中让会吼叫的事物吼叫。
 * 	在main方法中创建狗类对象(dog)、猫类对象(cat)、G类对象(g),用
 * 	g调用makecry方法,让狗和猫吼叫。
 */

//定义一个接口CanCry,描述会吼叫的方法public void cry()
interface CanCry {
    public void cry() ;
}

//猫类
class Cat implements CanCry {
    @Override
    public void cry() {
        System.out.println("我是猫,我的叫声是喵喵喵");
    }
}

//狗类
class Dog implements CanCry {
    @Override
    public void cry() {
        System.out.println("我是狗,我的叫声是汪汪汪");
    }
}

//测试类
class G {
    public static void main(String[] args) {
        //创建G类对象
        G g = new G() ;
        //方式1:创建具体的对象名:接口多态
        //实际参数:需要传递接口 子实现类对象
        CanCry canCry = new Dog() ;
        g.makeCry(canCry);
        canCry = new Cat() ;
        g.makeCry(canCry) ;
        System.out.println("------------------------") ;
        //方式2:匿名对象
        g.makeCry(new Dog()) ;
        g.makeCry(new Cat());
    }
    //成员方法
    public void makeCry(CanCry c){
        c.cry();
    }
}

返回值问题

方法的返回值要么是基本数据类型,要么是引用数据类型。方法的返回值如果是基本数据类型,那么方法声明中是什么类型,使用对应的类型接收。这是前面学习方法时介绍的。后期我们学习的都是引用数据类型。

方法的返回值是引用数据类型时的分析:

  • (如果方法的返回值是)具体类:需要返回的是当前类的具体对象!
  • 抽象类:需要返回的是当前抽象类的子类对象(也可以用匿名对象方式返回——抽象类多态)
  • 接口:需要返回的是接口的子实现类对象(接口多态)

接口方式和继承方式的实现效果比较

我们对这两个方式分别举例说明,最后总结。

如果我们写了一个具体类,里面实现了很多功能(方法)。那么我们再定义一个类,想重写上面的部分方法时,就需要用到继承。那么用到继承就产生了方法重写,方法重写会将所有的公共访问方法都继承过来,这样就会导致有些方法我们即使不需要,但也被带了过来。

换成面向接口编程的方式开发会怎么样呢?如果我们写了一个接口并定义了一些抽象方法,那么新定义一个类去实现接口,就要实现接口中所有的方法。如果还要重写方法,我们再写一个接口,把我们想重写的方法放进去,新定义类时只要重写选择的方法就可以了。

我们不妨以生活中的例子描述一下。类就相当于买菜的时候去批发,要么全都要,要么都不要;接口相当于零售,你要一个或者多个或者全要都可以。

综上所述,接口的实现效果比继承的实现效果更灵活,更有优势。面向接口编程是我们以后开发的主要形式。

练习:USB接口

/**
 * 需求说明:
 *      在现实生活中,我们经常通过电脑的 USB 接口来使用一些设备,
 *      例如 mp3 、移动硬盘、优盘等。现在要求使用面向接口编程去模拟实现这个例子。
 *      实现步骤
 *      (1)创建 USB 接口,接口中只定义一个 work()方法。
 *      (2)创建 MP3 类并实现 USB 接口。
 *      (3)创建优盘类(U_Disk)并实现 USB 接口。
 *      (4)创建电脑类(Computer)并定义一个使用接口的方法 useMobile(USB u)。
 *      (5)测试类中分别创建对应的对象进行测试,MP3对象,优盘类对象,电脑对象)
 */

//电脑类
class Computer {
    //电脑就是本身使用移动设备,查入不同的设备,实现不同的功能!
    //将构造方法私有化
    private Computer(){}
    //提供静态功能
    public static void useMobile(USB u){ //测试的时候:方法的形式参数是一个接口
        u.work() ;
    }
}

//MP3类
class MP3 implements USB {
    @Override
    public void work() {
        System.out.println("可以听音乐了...");
    }
}

//U盘类
class U_Disk implements USB {
    @Override
    public void work() {
        System.out.println("可以拷贝文件了");
    }
}

//USB接口
interface USB {
    void work() ;
}

//测试类
public class Test {
    public static void main(String[] args) {
        //使用Compupter的功能
        USB usb  = new MP3() ; //接口多态
        Computer.useMobile(usb);

        usb = new U_Disk() ; //接口多态
        Computer.useMobile(usb) ;
        
        System.out.println("---------------------------------") ;

        Computer.useMobile(new MP3());
        Computer.useMobile(new U_Disk());
    }
}

内部类

把类定义在其他类的内部,这个类就被称为内部类。举个例子,一个类A中定义一个类B,那么类B就称为类A的内部类。

内部类的位置

按照内部类在类中定义的位置不同,可以分为以下两种格式:

  1. 成员内部类:在外部类的成员位置定义的类
  2. 局部内部类:在外部类的成员方法中定义的类

类中能定义内部类,类中能定义方法,方法中能定义内部类,但方法中不能定义方法。

成员内部类中的成员访问外部类的成员变量包括私有

成员内部类的使用

成员内部类和外部类的访问方式

成员内部类中的成员可以访问外部类的成员变量包括私有属性

外部类的成员方法访问成员内部类的方法,创建内部类对象并访问方法即可。格式如下:

	外部类名.内部类名 对象名 = new 外部类对象.内部类对象;

外部类访问成员内部类的成员方法,要把外部类的成员内部类当做是外部类的成员,按照格式去创建对象并访问。访问成员方法的格式有静态和非静态之分。

访问非静态方法:

	外部类名.内部类名 对象名 = new 外部类名.内部类名();

访问静态方法:可以是上面创建对象的访问方式,或者像下面这样访问:

	外部类名.内部类名 对象名 = 外部类名.内部类名.方法名();

一般来说,在实际开发中是不会这样使用的。因为一般内部类就是不让外界直接访问的。

成员内部类常见的修饰符

  • private:可以保证数据的安全性
  • static:使数据访问更方便

注意事项:

  • 如果成员内部类都是静态的,成员内部类的方法就与静态无关,方法都只能访问静态的外部类成员。

  • 非静态的成员内部类中不能存在静态方法。

面试题:内部类和外部类没有继承关系

/**
 * 看程序,补全代码,使程序在控制台输出30,20,10
 */

class Outer {
    public int num = 10; 
    class Inner { 
        public int num = 20; 
        public void show() { 
            int num = 30; 
            //补全这3处代码
            System.out.println(); 
            System.out.println(); 
            System.out.println(); 
        } 
    } 
}

class OuterDemo { 
    public static void main(String[] args) { 
        Outer.Inner oi = new Outer().new Inner(); 
        oi.show(); 
    } 
}

答案:

num
this.num
Outer.this.num 或者 new Outer().num

局部内部类的使用

局部内部类可以直接访问外部类的成员。可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类的功能。

局部内部类特点:局部内部类也依然访问外部类的成员变量,包括私有

面试题:局部内部类访问局部变量的条件

问题:局部内部类访问局部变量的时候,能访问吗?局部变量有什么要求?

解答:

jdk7及jdk7之前,局部变量必须显示加入final修饰,否则访问会报错。而jdk8已经将jvm优化了,此时的num2是个常量!

局部变量的生命周期是随着的方法的调用而存在,随着方法的调用结束而消失。当前这个方法结束之后,num2局部变量应该就不存在了,但是我们还在使用内部类对象访问它里面的成员方法。对象不会立即被垃圾回收器立即回收,而是在空闲时回收掉没有更多引用的对象。所以此时这些变量都是常驻内存,应使用final将其变为常量。

权限修饰符

publicprotected默认private
同一类中
同一包的子类,其他类
不同包子类
不同包其它类

其它修饰符的使用

  • static:结合自定义常量使用,可结合final使用

    	public static final 数据类型 变量名 = 初始化数据;
    

    static还可以在工具类中使用,工具类中的构造方法私有化,里面的方法都会加入static,使用类名访问。

  • abstract:一般是修饰类,当作抽象类来使用。还可以在成员方法中定义,比如在抽象类中定义:

    	public abstract 返回值类型 方法名(参数列表) ;
    

    abstract在接口中定义的抽象方法中abstract可以省略

包及代码分层的含义

包就是文件夹(目录)。我们在开发项目的时候,不可能将所有的java文件都放在一个包下。所以真实的开发环境中包是需要针对代码分层的。

代码中包的分类

com.xxx.pojo/entity/domain:存储的是符合”JavaBean规范“的、描述现实世界事物的实体类。这个包下会将属性私有化,并对外提供公共的访问方法setter and getter。它(在分布式项目中)可以实现序列化接口(serializable接口)。

com.xxx.service:业务接口层,也叫服务层,是用来实现功能的。

com.xxx.dao:数据库访问层,也叫持久层,它是数据访问的接口层,通过JDBC连接数据库。

com.xxx.controller:控制层。用来调用业务层数据方法,利用前后端的交互技术,进行数据的视图的渲染!

Object类的两个常用方法

每个类都有Object作为超类(父类),所有的类都默认继承自Object

常用方法

public final Class getClass():获取当前正在运行的Class类对象(字节码文件对象)

在Class类中,public String getName()用于获取当前类或者接口的名称,以字符串形式返回

public int hashCode():理解 “一个地址值”,不是实际意义的地址值,它是经过底层的哈希算法(hash)算出来的

hashcode的源码:

	public native int hashCode();

native修饰的方法是本地方法,由非Java语言实现。底层是c相关的语言

public String toString():返回对象的字符串表示形式,结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法。

toString的源码:

	public String toString() {
        //包名.类名 + @ + 十六进制数据
    	return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

重写toString方法时使用开发环境提供的”模板“

public boolean equals(Object obj):比较对象是否相等,引用该类型比较的是地址值是否相同

==和equals的区别

==:如果连接都是两个基本数据类型:比如在int中比较的是数据值是否相等。如果连接的是引用类型,那么比较的是地址值是否相同

equals()是Object类的方法

equals的源码:

	public boolean equals(Object obj) {
    	return (this == obj);
	}

如果我们不重写Object的equals方法,默认比较的是两个引用类型的地址值是否相同,如果重写了equals方法而且同时重写了hashCode(),则比较的是成员信息是否相同!

注意:无论何时覆盖该方法equals(),通常需要覆盖hashCode方法

博客难免会产生一些错误。如果写的有什么问题,欢迎大家批评指正。

标签:Java,内部,对象,之路,接口,访问,week4day2,方法,public
来源: https://blog.csdn.net/weixin_43527493/article/details/122704304

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有