[后端基础]Java基础入门(二)

目录

String

常用的String方法:

equals和==的区别

Stringbuilder(重要)

Stringbuffer

Stringjoiner

集合

单列集合collection

List

ArrayList

LinkedList

Set

HashSet

TreeSet

LinkedHashSet

treeSet和hashSet区别

双列集合map

HashMap

TreeMap

LinkedHashMap

不可变集合

可变参数

多态

特点:

异常

异常的种类

异常处理

try-catch:

throws抛出异常

抽象类

接口

内部类

匿名内部类

lambda表达式

包装类

迭代器

常用方法:

泛型

泛型通配符

作用与好处


String

String三种常见创建方式:

  1. String 变量名 = "";//使用常量串
  2. String 变量名 = new String("");//new String对象
  3. char[] array = {"","",""}; String 变量名 = new String(array) //使用字符数组

String是一个类,所以String是一个引用对象,变量名存储的不是值而是地址。

底层由private final修饰的字符数组。

常用的String方法:

方法用法
int length()求字符串长度
boolean isEmpty()判断是否为空
boolean equals(str)判断字符串内容是否一致
int compareTo(str)比较字符串

char charAt(int index)

返回index位置上字符,如果index为负数或者越界

int indexOf(int i)

int indexOf(int i,int fromIndex)

返回i第一次出现的位置,没有返回-1

从fromIndex开始返回i第一次出现的位置,没有返回-1

也可查找字符串,同int用法

toLowerCase/toUpperCase大小写转换
str.replace('','')替换
String[] split("分隔符")拆分字符串,获得分隔符两边的字符串,不包含分隔符

subString(int index1,int index2)

subString(int index)

截取,从index1开始,到index2结束,左闭右开。

从下标开始截取一直到字符末尾

trim()删除字符串开头结尾的空白字符(空格, 换行, 制表符等).

compare方法:与equals返回true/false不同,compare返回一个int值

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
  2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

String.java是这样重写compareTo函数的:

 public int compareTo(String anotherString) {
        int len1 = value.length;//本字符串的长度
        int len2 = anotherString.value.length;//另外一个字符串长度
        int lim = Math.min(len1, len2);//去最小值
        char v1[] = value;//将字符串转化为数组
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;//返回的是首个不同字符的ASCII相减值
            }
            k++;
        }
        return len1 - len2;
    }

equals和==的区别

==:比较基本数据类型时,比较的是值;比较引用类型时,比较的是地址

equals:Object的equals()底层是用==写的,所以比较的也是地址;但是,重写的equals()比较的是值

Sring类本身被final修饰,而Sring类里面的字符数组value,是被private final修饰的
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
我们常说的String不能被修改是指String类里面的value数组不能更改,而不能更改的原因并不是因为final,而是因为private,这是一个私有变量,要想更改必须通过调用set方法,但是原生String类中并没有提供setvalue 方法,所以没有办法更改。

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。Java中的StringBuffer和StringBuilder是用于处理字符串的可变对象;这两种每次操作不会产生新的String对象。

Stringbuilder(重要)

可变字符串,效率高,线程不安全。

方法用法
StringBuilder append(任意类型)添加字符串
StringBuilder reverse()字符串反转
int length()获取长度
String toString()变成字符串

常在字符串拼接、反转时使用

Stringbuffer

可变字符串,效率低,线程安全。多线程操作大量数据,用StringBuffer。

Stringjoiner

拼接字符串时可以设置起始/结束/间隔符号,方便拼接

两种构造方法:new StringJoiner(间隔符号),new StringJoiner(间隔符号,开始符号,结束符号)

集合

数组长度固定,集合大小可以变。数组可以存储基本数据类型和引用类型,集合中存储引用数据类型(存储的为对象的内存地址)。数组中只能存储同一种类型成员集合中可以存储不同类型数据(一般情况下也只存储同一种类型的数据)

单列集合collection

List

List存储有序(插入顺序和取出顺序一致),可重复数据,有下标,下标从0开始

ArrayList

常用方法:

方法名说明
boolean add(E e)添加元素,成功返回true
boolean remove(E e)删除指定元素,成功返回true
E remove(int index)删除指定索引的元素,返回被删除元素
E set(int index,E e)修改指定索引元素,返回原来的元素
E get(int index)获取指定索引元素
int size()获取集合长度

底层原理:

线程不安全

LinkedList

底层是双链表,查询慢、增删快。

Set

存储无序,不可重复数据,无下标

Set接口继承了Collection接口,含有许多常用的方法。

int size();返回集合的长度
boolean isEmpty();判断集合是否为空
boolean  contains(Object o);是否包含某个值
boolean add(E e);添加元素
boolean remove(Object o);删除元素

HashSet

无序,不重复,无索引

HashSet的底层是通过HashMap实现。

Cloneable:实现了clone()方法可以实现克隆功能
Serializable:表示可以被序列化传输。

TreeSet

可排序,不重复,无索引

它继承了AbstractSet抽象类,实现了NavigableSet,Cloneable,Serializable接口。它是非线程安全的,TreeSet是基于TreeMap实现的
TreeMap是通过红黑树实现的。

hashSet去重的方法是hashcode和equals方法判断相同则覆盖,TreeSet是通过compareTo方法的返回值来判断是否相同,如果返回值为0则认定是重复元素

LinkedHashSet

有序,不重复,无索引

LinkedHashSet是hashSet子类,是一个哈希表和链表的结合,且是一个双向链表
并且linkedHashSet是一个非线程安全的集合。如果有多个线程同时访问当前linkedhashset集合容器,并且有一个线程对当前容器中的元素做了修改,那么必须要在外部实现同步保证数据的准确性。
LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素,它继承于 HashSet,其所有的方法操作上又与 HashSet 相同

treeSet和hashSet区别

1、TreeSet 是二叉树(红黑树)实现的,Treeset中的数据是自动排好序的,不允许放入null值。

2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复。

3、HashSet要求放入的对象实现HashCode()和equals()方法,TreeSet要求放入的对象继承Comparable接口并实现compareTo方法或者在建TreeMap对象时,传入一个Comparator接口,并实现里面的compare方法

双列集合map

存储一 一对应的键值对,键+值称为键值对,即键值对对象(Entry对象)。

特点:键不能重复,值可以重复;键和值是一一对应的

方法名说明
V put(K key,V value)添加元素
V remove(Object key)根据键删除元素
void clear()移除所有键值对
boolean containsKey(Object key)判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含指定的值
boolean isEmpty()判断是否为空
int size()获取长度,即键值对个数

添加时,如果键不存在则是添加;键存在则是覆盖

HashMap

hashMap特点由键的特点决定,键是无序,不重复,无索引的(set集合特征)

底层和hashSet一样,哈希表结构。通过hashCode和equals方法保证键的唯一。如果键存储自定义对象,需重写这两个方法。

TreeMap

可排序,不重复,无索引

 两种都写以第二种为准

LinkedHashMap

键是有序,不重复,无索引

不可变集合

在List、Map、Set接口中,都存在静态的of方法,可以获取一个不可变集合。不能添加、删除、修改数据。它的参数是有上限的,最多20个参数,10个键值对。创建多个键值对可以用ofEntries(),jdk 10以后可以通过copyOf()创建不可变集合

可变参数

格式:类型... 变量名<=>数据类型[] 变量名

要求:形参中可变列表只能写一个,且必须在最后。

多态

同类型对象,表现出不同形态

父类引用指向子类对象 -> 父类类型 对象名 = 子类对象

特点:

变量调用:编译看左边,运行也看左边

原因:子类继承父类成员变量,根据数据类型确定调用的父类成员变量

方法调用:编译看左边,运行看右边

原因:子类重写父类方法,在虚方法表中覆盖了父类方法

多态前提:有继承关系,有父类引用指向子类对象

好处:使用父类类型作为参数,可以接受所有子类对象,体现多态的拓展性和便利。实现解耦合,便于扩展维护

弊端:无法访问子类的特有功能,必须强制类型转换,才能使用

异常

异常的种类

throwable 下的errorexception两种

Error一般是比较严重的问题(比如:java内部系统错误,资源耗尽等),所以我们一般不对Error进行异常处理,通常要对我们的代码逻辑进行思考改进。

exception也分两类

编译时异常,运行时异常。unchecked exception包括运行时异常和error类,其他所有异常称为检查(checked)异常。

一些常见的异常:

ClassCastException //类型转换异常,IndexOutOfBoundsException //数组越界异常

NullPointerException //空指针,ArrayStoreException //数组存储异常

NumberFormatException //数字格式化异常,ArithmeticException //数学运算异常

NoSuchFieldException //反射异常,没有对应的字段,ClassNotFoundException //类没有找到异常

IllegalAccessException //安全权限异常

异常处理

try-catch:

try {
       //可能出现异常的代码
     } catch (异常类型 对象) {
            //异常执行代码
     }finally {
            //最后执行的部分
     }

finally部分无论是否出现异常都会执行,除非之前代码有system.exit(0)退出jvm或使用了Thread.stop()关闭线程。return不会影响finally的执行

throws抛出异常

使用throws关键字在类名后面抛出异常类型可以多个

格式:权限修饰符 返回值类型 类名 throws 异常类型1,异常类型2{}

注意:需要自己处理的异常千万别抛出,自己处理不了的问题一定要抛出去,若自己能处理的异常一直使用throws抛出的话,最终会交给Java虚拟机处理该异常,一旦出错,会直接将错误抛到页面或客户端,会造成用户体验性不好或者代码泄露。

throws和throw区别

throw是方法内部将异常对象创建出来的;

throws是方法声明时,将异常抛出给调用者的;

抽象类

abstract修饰的类,抽象类有构造方法但不能被实例化,抽象类中可以有抽象方法(抽象类可以没有抽象方法,但有抽象方法的类一定是抽象类),也可以有非抽象方法。其他类继承抽象类重写抽象方法,可以不重写,但要变成抽象类

接口

interface修饰的特殊抽象类(没有class修饰),没有构造方法。接口的方法中只能是抽象方法静态方法(此时要有方法体,static修饰)、默认方法(此时要有方法体,default修饰),后两个是jdk8新增的。

默认方法的使用场景包括:

  • 为接口添加新的方法,而不会破坏已有代码的兼容性。
  • 允许接口提供默认实现,从而减少实现类的工作量。

静态方法的使用场景包括:提供与接口相关的工具方法,这些方法可以在接口中定义为静态方法。

默认方法可以解决接口升级的问题,使得我们可以在不破坏已有代码的情况下向接口中添加新的方法。静态方法可以定义通用的工具方法,使得我们可以在不同的实现类中重复使用这些方法。

接口和其他类不一样,接口可以多继承

抽象类和接口区别:

抽象层次不同。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口只是对类行为进行抽象。继承抽象类是一种"是不是"的关系,而接口实现则是 "有没有"的关系。

内部类

类的五大成员:属性,方法,构造方法,代码块,内部类

定义:在一个类里定义的类被叫做内部类

特点:内部类可以访问外部类的成员,包括私有。外部类必须创建对象才能访问内部类

分类:成员内部类,静态内部类,局部内部类,匿名内部类

成员内部类:写在外部类的成员位置,成员内部类可以被修饰符修饰

获取成员内部类对象:1.通过外部类方法 2.外部类名.内部类名 对象名 = 外部类对象.内部类对象

方式一可以获取被private修饰的内部类,外部类方法返回一个内部类对象

如果外部类的成员变量和内部类成员变量重名,Outer.this.变量名获取外部类成员变量

静态内部类:由static修饰的内部类,只能访问外部类的静态变量和静态方法,访问非静态需创建对象。创建对象格式:外部类名.内部类名 对象名 = new 外部类名.内部类名。

调用静态内部类方法:非静态:使用对象调用;静态:外部类名.内部类名.方法名()。

局部内部类:定义在方法里的内部类,类似局部变量

外界无法直接访问,需要在方法里创建对象,可以直接访问外部类成员和方法内的局部变量

匿名内部类

没有名字的内部类,一般只使用一次才这样写。可以在成员位置/局部位置

格式:new 类名或接口名{重写方法},"{}"包括的才是匿名内部类,类名或接口名是匿名内部类要继承或实现的。

lambda表达式

函数式编程

是一种思想,忽略面向对象的复杂语法,强调做什么,而不是谁去做。lambda表达式就是这思想的体现。

函数式接口

有且只有一个抽象方法的接口,接口上方可以添加@functionalInterface 注解

lambda表达式

是对匿名内部类的简化,且只能简化函数式接口的匿名内部类写法。把函数作为一个方法的参数。

格式:(参数类型1 变量1,参数类型2 变量2)->{方法体}

省略写法:参数类型可以省略;如果只有一个形参,()可以省略;方法体只有一行,{}、分号、return可以同时省略;

双冒号(::)

Java 8中被用作方法引用,方法引用是与lambda表达式相关的一个重要特性。方法给接口提供的参数和他接收的返回,和你现有某个实现完全一致,就可以进一步进行简化,称为方法引用。使用lambda表达式会创建匿名方法, 但有时候需要使用一个lambda表达式只调用一个已经存在的方法(不做其它)。

语法(类名/类实例名::方法名):

  1. 静态方法引用(static method)语法:classname::methodname 例如:Person::getAge
  2. 对象的实例方法引用语法:instancename::methodname 例如:System.out::println
  3. 对象的超类方法引用语法: super::methodname
  4. 类构造器引用语法: classname::new 例如:ArrayList::new
  5. 数组构造器引用语法: typename[]::new 例如: String[]:new
     

例子:

forEach:

  //初始版本
 for (Dog dog : dogs) {
            System.out.println(dog);
        }
 //实现 new Consumer<?> 接口的匿名实现类,重写accept抽象方法
 dogs.forEach(new Consumer<Dog>() {
            @Override
            public void accept(Dog dog) {
                System.out.println(dog);
            }
        });
  //lambda简化
  dogs.forEach((Dog dog) -> {
                    System.out.println(dog);
                });
  //双冒号简化,accept
  dogs.forEach(System.out::println);
  //使用out.println()作为accept抽象方法的实现
  //accept的形参和返回值与println()一样
  public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }
 // 创建一个数组
        ArrayList<Integer> numbers = new ArrayList<>();

        // 往数组中添加元素
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        System.out.println("ArrayList: " + numbers);

        // 所有元素乘以 10
        System.out.print("更新 ArrayList: ");
       
        // 将 lambda 表达式传递给 forEach
        numbers.forEach((e) -> {
            e = e * 10;
            System.out.print(e + " ");
        });
    }
//原本应该写为:

.forEach(element -> {

System.out.println(element)

})

//但是System.out.println的参数和传递的参数element 的类型完全匹配,所以这样的时候就可以简化为:

.forEach(System.out::println)



//1. Lambda表达式:
person -> person.getName();
//可以替换成:
Person::getName

//2. Lambda表达式:
() -> new HashMap<>();
//可以替换成:
HashMap::new

包装类

原始类型包装类型
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

装箱:将基础类型转化为包装类型。

拆箱:将包装类型转化为基础类型。

当基础类型与它们的包装类有如下几种情况时,编译器会自动帮我们进行装箱或拆箱:

  • 赋值操作(装箱或拆箱)
  • 进行加减乘除混合运算 (拆箱)
  • 进行>,<,==比较运算(拆箱)
  • 调用equals进行比较(装箱)
  • ArrayList、HashMap等集合类添加基础类型数据时(装箱)

迭代器

Iterator类,可以遍历Collection类型(List和set),不依赖索引遍历。

常用方法:

Iterator<E> iterator:返回迭代器对象,默认指向当前集合的0索引

boolean hasNext():判断当前位置是否有元素,有返回true,没有则false

next():获取当前元素,并将迭代器移向下一元素。

遍历时不能使用集合的增删方法,只能使用迭代器的方法(迭代器只有删除的方法)

增强for循环的底层就是迭代器(增强for只能遍历单列集合和数组)

泛型

格式:<数据类型>(默认:Object),只支持引用类型,不能写基本数据类型。指定数据类型后只能传入该类型或其子类的数据。

好处:统一数据类型,将运行问题提前到了编译阶段,避免了类型转换异常

java的泛型是伪泛型,只在编译阶段有效(兼容之前版本)

泛型种类:泛型类,泛型方法,泛型接口

泛型类:修饰符 class 类名<数据类型>

泛型方法:修饰符 <类型> 返回值类型 方法名(类型 变量名)

泛型接口:1.实现类直接给出数据类型 2.实现类延续泛型,创建对象时再确定数据类型

常见泛型字母代表数据类型:T,E,K,V(type,element,key,value)

泛型不具备继承性,但数据有继承性

泛型通配符

?:代表不确定的类型,?extends E:表示可以传递E及其子类的数据,

?super E:表示可以转递E及其父类的数据。

作用与好处

泛型的作用是为了统一集合中存放的数据类型。

好处:

1、类型安全
泛型的主要目的是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在非常高的层次上验证类型假设。

通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误就可以在编译时被捕获了。将类型检查从运行时挪到编译时有助于Java开发人员更早、更容易地找到错误,并可提高程序的可靠性。

2、消除强制类型转换
泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3、更高的效率
在非泛型编程中,将筒单类型作为Object传递时会引起Boxing(装箱)和Unboxing(拆箱)操作,这两个过程都是具有很大开销的。引入泛型后,就不必进行Boxing和Unboxing操作了,所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。

4、潜在的性能收益
泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,Java系统开发人员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的JVM的优化带来可能。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值