Java学习之路之week4day2
作者:互联网
向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的内部类。
内部类的位置
按照内部类在类中定义的位置不同,可以分为以下两种格式:
- 成员内部类:在外部类的成员位置定义的类
- 局部内部类:在外部类的成员方法中定义的类
类中能定义内部类,类中能定义方法,方法中能定义内部类,但方法中不能定义方法。
成员内部类中的成员访问外部类的成员变量包括私有
成员内部类的使用
成员内部类和外部类的访问方式
成员内部类中的成员可以访问外部类的成员变量包括私有属性
外部类的成员方法访问成员内部类的方法,创建内部类对象并访问方法即可。格式如下:
外部类名.内部类名 对象名 = 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将其变为常量。
权限修饰符
public | protected | 默认 | 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