Java学习之路之week4day3

向Java程序员的目标前进!

day17

面向对象—续7

匿名内部类

顾名思义,匿名内部类就是没有名字的类,它是内部类的简化写法。

一般来说,开发很少使用具体类的匿名内部类,因为具体类本身就可以创建对象。

匿名内部类的前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类。

匿名内部类的格式

在一个类中的某个局部位置使用

	new 类名(一般情况下:都是抽象类)或接口名() {
        重写抽象类或者接口的抽象方法(){
            ...
        }
    };

匿名内部类的本质

是一个继承了该抽象类或者实现了接口的子类对象,本质还是多态

匿名内部类的应用场景

在抽象类和接口中使用最多,其中接口使用最多!

匿名内部类在开发中的使用

  • 形参问题
    • 如果方法形式参数是一个抽象类,调用方法的时候实际参数应该传递的当前抽象类的子类对象!
    • 如果方法的形式参数如果是一个接口类型,调用方法的时候,需要传递接口的子实现类对象
  • 返回值问题
    • 方法的返回值如果是一个接口,需要接口的子实现类对象

JDK8新特性——拉姆达表达式

当接口中有且仅有一个抽象方法的时候,那么这个接口可以称为"函数式接口"。

函数式接口在实现方法的时候,有一个”->“箭头直接可以实现接口的方法

下面以例子分别展示接口的匿名内部类写法和拉姆达表达式写法

接口的匿名内部类写法

	ld.show(new Love() { 
        @Override
        public void love() {
            System.out.println("爱学cs的小陈");
        }
    });

拉姆达表达式写法

	ld.show( //接口的匿名内部类很多
		()->{
				System.out.println("爱学cs的小陈");
            }
    );

面试题:匿名内部类的使用

/**
 * 看程序,补全代码,是程序在控制台输出"hello world"
 * 考查匿名内部类的使用
 */

interface Inter{
    void show() ;
}
class Outer{
     //此处补全代码
}
public class Test {
    public static void main(String[] args) {
        Outer.method().show();
    }
}

解析:

首先分析代码第14行,既然能用Outer直接调用method(),说明method是静态方法。method()后还可以调用show(),说明method()不仅存在返回值类型,返回的还是一个接口类型Inter。我们需要返回一个接口,那么就需要返回的接口的子实现类对象。但是程序现在没有子实现类名,那么最后就直接使用接口的匿名内部类。

答案:

	public static Inter method(){
        return new Inter(){
            @Override
            public void show() {
                System.out.println("hello world");
            }
        };
    }

Object类的几个方法—续

Object的clone方法

protected native Object clone() throws CloneNotSupportedException:创建并返回此对象的副本。

clone的复制取决于对象的类,但是一般情况下是浅克隆,我们讨论的也仅仅是浅克隆。

clone方法是受保护的,而且是本地方法。如果不能实现Cloneable接口,则会抛出克隆不支持的异常(CloneNotSupportedException)。通常情况下,对于任意对象

x,判断的表达式是:

	x.clone().equals(x)

这个结果将会是true。通过内存图来解释clone(浅克隆)的原理

在这里插入图片描述

上面的图解说明了:

  • 产生的克隆对象只在栈内存中开辟区域
  • 克隆对象与原对象的空间地址值是相同的

常用类

Scanner类

public boolean hasNextXXX(){} :判断下一个录入的数据是否为XXX类型

注:XXX就是对应的数据类型

public XXX nextXXX():以XXX形式扫描输入的下一个标记。

如果定义接收的数据类型和实际数据类型不匹配(实际的输入String,而接收的int),那么系统就会报java.util.InputMismatchException的错误。

键盘录入的细节

问题:分别定义两个数据并录入,先录入String再录入int,没问题。先录入int再录入String,有问题。

原因:在录入int数据的时候,按了回车键。下一个录入的是String类型数据,录入时系统将换行当作空字符进去了,所以第二个数据没有录入程序就结束了。

解决方案

  1. 使用public String next() 方法,录入指定的字符串内容
  2. 仍然使用nextLine方法录入String。但是在录入String之前,重新创建一个新的键盘录入对象。

总结与建议:今后如果有int类型的数据需要录入,都可以拿String的nextLine方法接收(前提是录入格式要对)

String类

String类就是字符串类,数据值是常量,一旦被创建,其值就不能被更改。字符串类的底层是字符数组。

创建格式(建议的格式)

	String 变量名 = "数据值";

String对象的数据值在创建时会存在与方法区的字符串常量池中。在赋值时会先在常量池中查找是否存在相同的字符串常量。如果存在就会指向常量池的对应常量地址值,否则会在常量池中开辟空间。

String类的特点

  1. 字符串不变:字符串的值在创建后不能被更改。
  2. 共享性:因为String对象不可变,所以具有共享性。
  3. 重写了toString:String类型已经重写了Object的toString()功能。所以直接输出对象名,结果是对应的数据值。

String的构造方法

String():空参构造

当以空参构造创建String对象并直接输出时,将返回""(空的字符串)

String(byte[] bytes):有参构造,里面是字节数组(将byte[]转换为String)。作用是用平台默认字符集(现在是"UTF-8")解码字符数组,并构造一个新的字符串。

String(byte[] bytes, int offset, int length):将字节数组的指定部分解码并组成字符串。

byte[] bytes:字节数组对象

int offset:开始的位置

int length:指定的长度

String(char[] value):使字符数组组成新的字符串

String(char[] value, int offset, int count):使部分字符数组组成新的字符串

char[] value:字符数组对象

int length:指定的长度

String(String original) :以括号里的字符串创建新的字符串对象(就是复制),参数为字符串常量值。

面试题:length()方法

Q:数组中有没有length(),String类中有没有length(),集合中有没有length()方法?

A:数组中没有length方法,有一个叫做length的属性。

String类中有length方法,是用来获取字符串长度的

集合中没有length方法,但是有size方法,是用来获取集合的元素数量

面试题:创建String对象的方式区别

Q:实际开发中,将常量赋值给字符串、new String(“常量”)、给String对象赋值为null和给和String对象赋值为""有什么区别?

A:四种方式是有区别的。

String对象赋值为null,则String对象为空对象,此时如果String对象的长度,则会报空指针异常。

String对象赋值为“”,则String对象为空字符序列,此时String对象的长度为0,可以用concat函数进行字符串的拼接。

.concat(String str); 拼接功能函数

注意:空对象和空字符串不是一个意思!
“”:空字符序列(空字符串),依然可以使用String类型里面的所有功能
null:空对象,不能在使用String的方法,一旦使用系统就会报空指针异常NullPointerException

采用将常量赋值给字符串的方式,是一种推荐的方式。采用此种方式后,JVM将直接在常量中找是否存在常量。如果存在,则返回该常量的内存地址值并返回,否则JVM将在常量池中开辟空间、创建对象。

如果在代码中直接new了String常量,这会使JVM在内存中创建两个对象(栈内存中对象、堆内存中对象)。JVM将按照创建对象的方式进行指针的引用。在堆内存中,创建的对象还会有常量标记,指向常量池的变量。所以这是一种不推荐的方式。

String常用的判断功能

1. public boolean contains(String s):字符串中是否包含指定的字符(连续的字符序列)(重点)
2. public boolean endsWith(String suffix):是否以指定的字符串结尾
3. public boolean startsWith(String prefix):是否以指定的字符串开头
4. public boolean isEmpty():判断字符串内容是否空字符,如果长度为0,结果为true
5. public boolean equals(Object anObject):重写了Object类的equals方法,以区分大小写的方式比较内容是否相同(重点)
6. public boolean equalsIgnoreCase(Object anObject):以不区分大小写的方式比较内容是否相同

String的equals方法的源码分析

/**
 * String的equals方法源码
 */
public final class String{
    //定义字符数组
    private final char value[];
    public boolean equals(Object anObject) {
        // 进行内存地址值的比较,如果相同则返回true
        if (this == anObject) {
            return true;
        }
        // 判断对象是否为String类型的实例
        if (anObject instanceof String) {
            // 如果是,向下转型为String
            String anotherString = (String)anObject;
            // 取字符串的长度,相当于this.length
            int n = value.length;
            // 比较字符串和传入的字符串长度
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                // 将两个字符串进行逐个比较
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
	} 
}

String的获取功能

public char charAt(int index):获取指定索引处(索引就是位置的意思,从0开始)的字符值
public String concat(String str):拼接获取新的字符串,另外一种方式的拼接方法是"+"
public int indexOf(int ch):返回指定字符第一次出现的字符串内的索引值
public int indexOf(String str):返回指定字符串中子字符串第一次出现的索引值
public int lastIndexOf(int ch):返回指定字符最后一次出现的索引值
public int lastIndexOf(String str):同上
String substring(int beginIndex):从指定位置开始默认截取到末尾,返回一个新的字符串
String substring(int beginIndex, int endIndex):从指定位置开始截取到指定位置结束(从beginIndex到endIndex-1处都会被取到),返回的一个字符串

String的拆分功能

public String[] split(String regex):按照指定的分割符号,将字符串拆分成字符串数组

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值