Java基础教程与面向对象教程(精编)

Java基础知识点整合

概念知识

面向对象的三大特性

封装,继承,多态

Java封装

封装的概念

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

要访问该类的代码和数据,必须通过严格的接口控制

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

封装的优点
    1. 良好的封装能够减少耦合。
    1. 类内部的结构可以自由修改。
    1. 可以对成员变量进行更精确的控制。
    1. 隐藏信息,实现细节。
实现封装的步骤
  • 1.修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
    private String name;
    private int age;
}

这段代码中,将 nameage 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。

  • 2.对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class Person{
    private String name;
    private int age;public int getAge(){
      return age;
    }public String getName(){
      return name;
    }public void setAge(int age){
      this.age = age;
    }public void setName(String name){
      this.name = name;
    }
}

采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

Java继承

继承的概念

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承的访问权限

Java 中有三个访问权限修饰符:private、protected 以及 public,如果不加访问修饰符,表示包级可见。

可以对类或类中的成员(字段以及方法)加上访问修饰符。

  • 类可见表示其它类可以用这个类创建实例对象。
  • 成员可见表示其它类可以用这个类的实例对象访问到该成员;

protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。

如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别:这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里氏替换原则。

字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。

继承的特性
  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字

继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。

extends关键字

在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, String myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
public class Penguin  extends  Animal{ 
}
implements关键字

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

public interface A {
    public void eat();
    public void sleep();
}
public interface B {
    public void show();
}
public class C implements A,B {
}
super 与 this 关键字

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

  • 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
  • 访问父类的成员:如果子类重写了父类的中某个方法的实现,可以通过使用 super 关键字来引用父类的方法实现。

Using the Keyword super

this关键字:指向自己的引用。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}
final关键字

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:

  • 声明类:
final class 类名 {//类体}
  • 声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}

:实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final

继承的其他问题

接口是否可继承接口?

可以,比如List 就继承了接口Collection

抽象类是否可实现(implements)接口?

可以,比如MouseAdapter鼠标监听适配器 是一个抽象类,并且实现了MouseListener接口

抽象类是否可继承实体类(concrete class)?

可以,所有抽象类,都继承了Object

Java多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:

img

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

多态的分类

多态分为编译时多态和运行时多态。

  • 编译时多态:方法的重载
  • 运行时多态:指程序中定义的对象引用所指向的具体类型在运行期间才确定。

运行时多态有三个条件

多态的存在有三个前提:

  • 要有继承关系
  • 子类要重写父类的方法
  • 父类引用指向子类对,
多态的优点
    1. 消除类型之间的耦合关系
    1. 可替换性
    1. 可扩充性
    1. 接口性
    1. 灵活性
    1. 简化性
多态的缺点

多态不能使用子类特有的成员属性和子类特有的成员方法。

这就是多态的魅力吧,虽然它有缺点,但是它确实十分灵活,减少多余对象的创建,不用说为了使用子类的某个方法又去重新再堆内存中开辟一个新的子类对象。

多态存在的三个必要条件
  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

img

抽象类与接口

抽象类

抽象类和普通类最大的区别是:

抽象类不能被实例化,需要继承抽象类才能实例化其子类

public abstract class AbstractClassExample {

    protected int x;
    private int y;

    public abstract void func1();

    public void func2() {
        System.out.println("func2");
    }
}
public class AbstractExtendClassExample extends AbstractClassExample {
    @Override
    public void func1() {
        System.out.println("func1");
    }
}
接口

接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。

从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。

在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。

接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。

接口的字段默认都是 static 和 final 的。

public interface InterfaceExample {
    void func1();

    default void func2(){
        System.out.println("func2");
    }

    int x = 123;
    // int y;               // Variable 'y' might not have been initialized
    public int z = 0;       // Modifier 'public' is redundant for interface fields
    // private int k = 0;   // Modifier 'private' not allowed here
    // protected int l = 0; // Modifier 'protected' not allowed here
    // private void fun3(); // Modifier 'private' not allowed here
}
public class InterfaceImplementExample implements InterfaceExample {
    @Override
    public void func1() {
        System.out.println("func1");
    }
}
抽象类与接口类的比较
  • 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。
  • 而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
    从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
  • 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
  • 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
使用情况选择

使用接口

  • 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable接口中的compareTo() 方法;
  • 需要使用多重继承。

使用抽象类:

  • 需要在几个相关的类中共享代码。
  • 需要能控制继承来的成员的访问权限,而不是都为 public。
  • 需要继承非静态static和非常量final字段。

在很多情况下,接口优先于抽象类,因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。

虚函数

虚函数的存在是为了多态。

Java 中其实没有虚函数的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。

重写

当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。

要想调用父类中被重写的方法,则必须使用关键字 super

多态的实现方式
  • 一:重写:

  • 二:接口

  • 三:抽象类和抽象方法

Java数据类型

String是类类型,不是基本类型。

基本类型 有八种:整型 (4种)字符型 (1种)浮点型 (2种)布尔型(1种)

image

image

Java变量

变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。

内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。

img

因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。

Java 的两大数据类型:

  • 内置数据类型
  • 引用数据类型
内置数据类型

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

byte:

  • byte 数据类型是8位、有符号的,以二进制补码表示的整数;
  • 最小值是 -128(-2^7)
  • 最大值是 127(2^7-1)
  • 默认值是 0
  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
  • 例子:byte a = 100,byte b = -50。

short:

  • short 数据类型是 16 位、有符号的以二进制补码表示的整数
  • 最小值是 -32768(-2^15)
  • 最大值是 32767(2^15 - 1)
  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
  • 默认值是 0
  • 例子:short s = 1000,short r = -20000。

int:

  • int 数据类型是32位、有符号的以二进制补码表示的整数;
  • 最小值是 -2,147,483,648(-2^31)
  • 最大值是 2,147,483,647(2^31 - 1)
  • 一般地整型变量默认为 int 类型;
  • 默认值是 0
  • 例子:int a = 100000, int b = -200000。

long:

  • long 数据类型是 64 位、有符号的以二进制补码表示的整数;
  • 最小值是 -9,223,372,036,854,775,808(-2^63)
  • 最大值是 9,223,372,036,854,775,807(2^63 -1)
  • 这种类型主要使用在需要比较大整数的系统上;
  • 默认值是 0L
  • 例子: long a = 100000L,Long b = -200000L。
    "L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。

float:

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
  • float 在储存大型浮点数组的时候可节省内存空间;
  • 默认值是 0.0f
  • 浮点数不能用来表示精确的值,如货币;
  • 例子:float f1 = 234.5f。

double:

  • double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
  • 浮点数的默认类型为double类型;
  • double类型同样不能表示精确的值,如货币;
  • 默认值是 0.0d
  • 例子:double d1 = 123.4。

boolean:

  • boolean数据类型表示一位的信息;
  • 只有两个取值:true 和 false;
  • 这种类型只作为一种标志来记录 true/false 情况;
  • 默认值是 false
  • 例子:boolean one = true。

char:

  • char类型是一个单一的 16 位 Unicode 字符;
  • 最小值是 \u0000(即为 0);
  • 最大值是 \uffff(即为 65535);
  • char 数据类型可以储存任何字符;
  • 例子:char letter = ‘A’;。

类型默认值

下表列出了 Java 各个类型的默认值:

数据类型默认值
byte0
short0
int0
long0L
float0.0f
double0.0d
char‘u0000’
String (or any object)null
booleanfalse
引用数据类型
  • 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
  • 对象、数组都是引用数据类型。
  • 所有引用类型的默认值都是null。
  • 一个引用变量可以用来引用任何与之兼容的类型。
  • 例子:Site site = new Site(“Runoob”)。

Java 常量

常量在程序运行时是不能被修改的。

在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:

虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。

byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。

当使用字面量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制。

和其他语言一样,Java的字符串常量也是包含在两个引号之间的字符序列。

字符串常量和字符常量都可以包含任何Unicode字符。

final double PI = 3.1415927;
byte a = 68;
char a = 'A'
int decimal = 100;
int octal = 0144;
int hexa =  0x64;
"Hello World"
"two\nlines"
"\"This is in quotes\""
char a = '\u0001';
String a = "\u0001";

Java特殊字符

Java语言支持一些特殊的转义字符序列。

符号字符含义
\n换行 (0x0a)
\r回车 (0x0d)
\f换页符(0x0c)
\b退格 (0x08)
\0空字符 (0x0)
\s空格 (0x20)
\t制表符
"双引号
单引号
\反斜杠
\ddd八进制字符 (ddd)
\uxxxx16进制Unicode字符 (xxxx)
Java自动类型转换

整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。

转换从低级到高级。

------------------------------------>byte,short,char> int> long> float> double 

数据类型转换必须满足如下规则:

    1. 不能对boolean类型进行类型转换。
    1. 不能把对象类型转换成不相关类的对象。
    1. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
    1. 转换过程中可能导致溢出或损失精度,例如:
int i =128;   
byte b = (byte)i;
  • 因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。
    1. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
(int)23.7 == 23;        
(int)-45.89f == -45

自动类型转换

必须满足转换前的数据类型的位数要低于转换后的数据类型,例如: short数据类型的位数为16位,就可以自动转换位数为32的int类型,同样float数据类型的位数为32,可以自动转换为64位的double类型。

强制类型转换

    1. 条件是转换的数据类型必须是兼容的。
    1. 格式:(type)value type是要强制类型转换后的数据类型 实例:

隐含强制类型转换

    1. 整数的默认类型是 int。
    1. 浮点型不存在这种情况,因为在定义 float 类型时必须在数字后面跟上 F 或者 f。
Java数据存储的缓存池
public class Main_1 {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        System.out.println(c == d);//true,缓存池
        System.out.println(e == f);//false,不在缓存池
        System.out.println(c == (a + b));//true
        System.out.println(c.equals(a + b));//true
        System.out.println(g == (a + b));//true
        System.out.println(g.equals(a + b));//false
        System.out.println(g.equals(a + h));//true
    }

使用==的情况:

如果比较Integer变量,默认比较的是地址值。
特例:如果比较的某一边有操作表达式(例如a+b),那么比较的是具体数值
使用equals()的情况:

无论是Integer还是Long中的equals()默认比较的是数值。
特例:Long的equals()方法,JDK的默认实现:会判断是否是Long类型
new Integer(123) 与 Integer.valueOf(123) 的区别在于:

new Integer(123) 每次都会新建一个对象
Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

基本类型对应的缓冲池如下:

boolean values true and false
all byte values
short values between -128 and 127
int values between -128 and 127
char in the range \u0000 to \u007F

Java String类

字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。

String 概览

String 被声明为 final,因此它不可被继承。

在 Java 8 中,String 内部使用 char 数组存储数据。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;
}

不可变的好处

    1. 可以缓存 hash 值

因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

    1. String Pool 的需要

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

注意:不是string创建后就默认进入池的,请看下方intern()
在这里插入图片描述

    1. 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。

    1. 线程安全

String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

创建字符串

创建字符串最简单的方式如下:

String str = "Runoob";

在代码中遇到字符串常量时,这里的值是 Runoob,编译器会使用该值创建一个 String 对象。

和其它对象一样,可以使用关键字和构造方法来创建 String 对象。

用构造函数创建字符串:

String str2=new String("Runoob");

String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:

String s1 = "Runoob";              // String 直接创建
String s2 = "Runoob";              // String 直接创建
String s3 = s1;                    // 相同引用
String s4 = new String("Runoob");   // String 对象创建
String s5 = new String("Runoob");   // String 对象创建

img

**注意:**String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了(详看笔记部分解析)。

如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类

字符串长度

用于获取有关对象的信息的方法称为访问器方法。

String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。

连接字符串

String 类提供了连接两个字符串的方法:

string1.concat(string2);
"Hello," + " runoob" + "!"
创建格式化字符串

我们知道输出格式化数字可以使用 printf() 和 format() 方法。

String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。

String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。

** String 方法

下面是 String 类支持的方法,更多详细,参看 Java String API 文档:

SN(序号)方法描述
1*char charAt(int index)
返回指定索引处的 char 值。
2int compareTo(Object o)
把这个字符串和另一个对象比较。
3int compareTo(String anotherString)
按字典顺序比较两个字符串。
4int compareToIgnoreCase(String str)
按字典顺序比较两个字符串,不考虑大小写。
5String concat(String str)
将指定字符串连接到此字符串的结尾。
6 boolean contentEquals(StringBuffer sb)
当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。
7static String copyValueOf(char[] data)
返回指定数组中表示该字符序列的 String。
8static String copyValueOf(char[] data, int offset, int count)
返回指定数组中表示该字符序列的 String。
9 boolean endsWith(String suffix)
测试此字符串是否以指定的后缀结束。
10* boolean equals(Object anObject)
将此字符串与指定的对象比较。
11 boolean equalsIgnoreCase(String anotherString)
将此 String 与另一个 String 比较,不考虑大小写。
12byte[]. getBytes()
使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
13byte[] getBytes(String charsetName)
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
14void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin)
将字符从此字符串复制到目标字符数组。
15 int hashCode() 返回此字符串的哈希码。
16int indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引。
17 int indexOf(int ch, int fromIndex)
返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
18 int indexOf(String str)
返回指定子字符串在此字符串中第一次出现处的索引。
19 int indexOf(String str, int fromIndex)
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
20 String intern()
返回字符串对象的规范化表示形式。
21 int lastIndexOf(int ch)
返回指定字符在此字符串中最后一次出现处的索引。
22 int lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
23 int lastIndexOf(String str)
返回指定子字符串在此字符串中最右边出现处的索引。
24 int lastIndexOf(String str, int fromIndex)
返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
25* int length()
返回此字符串的长度。
26* boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式。
27 boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
28 boolean regionMatches(int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等。
29 String replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
30 String replaceAll(String regex, String replacement)
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
31 String replaceFirst(String regex, String replacement)
使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
32String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串。
33String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串。
34* boolean startsWith(String prefix)
测试此字符串是否以指定的前缀开始。
35 boolean startsWith(String prefix, int toffset)
测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
36 CharSequence subSequence(int beginIndex, int endIndex)
返回一个新的字符序列,它是此序列的一个子序列。
37 String substring(int beginIndex)
返回一个新的字符串,它是此字符串的一个子字符串。
38 String substring(int beginIndex, int endIndex)
返回一个新字符串,它是此字符串的一个子字符串。
39*[ char] toCharArray()
将此字符串转换为一个新的字符数组。
40 String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
41 String toLowerCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
42* String toString()
返回此对象本身(它已经是一个字符串!)。
43 String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
44 String toUpperCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
45 String trim()
返回字符串的副本,忽略前导空白和尾部空白。
46 static String valueOf(primitive data type x)
返回给定data type类型x参数的字符串表示形式。
47 contains(CharSequence chars)
判断是否包含指定的字符系列。
48* isEmpty()
判断字符串是否为空。
String, StringBuffer and StringBuilder
    1. 可变性

String 不可变
StringBuffer 和 StringBuilder 可变

    1. 线程安全

String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步

对于三者使用的总结:

  • 1.如果要操作少量的数据用 String

  • 2.单线程操作字符串缓冲区下操作大量数据 StringBuilder

  • 3.多线程操作字符串缓冲区下操作大量数据 StringBuffer

String 和StringBuffer的区别?
String是immutable的,其内容一旦创建好之后,就不可以发生改变。

StringBuffer 是可以变长的,内容也可以发生改变
改变的原理是StringBuffer内部采用了字符数组存放数据,在需要增加长度的时候,创建新的数组,并且把原来的数据复制到新的数组这样的办法来实现。

初始化:可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符

扩容:尝试将新容量扩为大小变成原容量的1倍+2,然后if判断一下 容量如果不够,直接扩充到需要的容量大小。

String、StringBuffer、StringBuilder区别

String,StringBuffer与StringBuilder的区别

String Pool

**字符串常量池(String Pool)**保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。

当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中,然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。

String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
String s4 = s1.intern();
System.out.println(s3 == s4);           // true

如果是采用 “bbb” 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。

String s5 = "bbb";
String s6 = "bbb";
System.out.println(s5 == s6);  // true

参数运算

* Java的参数传递

Java 的参数是以值传递的形式传入方法中,而不是引用传递。

Java 的参数是以值传递的形式传入方法中,而不是引用传递。

以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。因此在方法中使指针引用其它对象,那么这两个指针此时指向的是完全不同的对象,在一方改变其所指向对象的内容时对另一方没有影响。

public class Dog {

    String name;

    Dog(String name) {
        this.name = name;
    }

    String getName() {
        return this.name;
    }

    void setName(String name) {
        this.name = name;
    }

    String getObjectAddress() {
        return super.toString();
    }
}
public class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        func(dog);
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        System.out.println(dog.getName());          // A
    }

    private static void func(Dog dog) {
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        dog = new Dog("B");
        System.out.println(dog.getObjectAddress()); // Dog@74a14482
        System.out.println(dog.getName());          // B
    }
}

如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。

class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        func(dog);
        System.out.println(dog.getName());          // B
    }

    private static void func(Dog dog) {
        dog.setName("B");
    }
}
值传递

实参传递给形参的是值 形参和实参在内存上是两个独立的变量 对形参做任何修改不会影响实参

代码示例如下:

public class Demo1 {
        public static void main(String[] args) {
                int b =20;
                change(b);// 实参  实际上的参数
                System.out.println(b);
        }
        public static void change(int a){//形参  形式上的参数
                a=100;
        }
}

结果:20

在这里插入图片描述

通俗的讲法就是:形参只是实参创建的一个副本,副本改变了,原本当然不可能跟着改变;

再通俗的讲法就是:

小明去餐厅吃饭,看见别人点的红烧肉挺好吃,九把服务员叫过来,说我要一份红烧肉,服务员从后厨拿来一份红烧肉,小明吃完了,但是他吃的红烧肉跟旁边那个人吃的是一份吗?当然不是。

引用传递

实参传递给形参的是参数对于 堆内存上的引用地址 实参和 形参在内存上指向 了同一块区域 对形参的修改会影响实参

public class Demo1 {
        public static void main(String[] args) {
                int [] a={1,2,3};
                System.out.println(a[0]);
                change(a);
                System.out.println(a[0]);
        }
        public static void change(int[] a ){
                a[0]=100;
        }
}

结果:1 100

在这里插入图片描述

由于引用传递,传递的是地址,方法改变的都是同一个地址中的值,

原来a[0]指向0x13地址,值是1,

后来在a[0] 指向的也是0x13地址,将值变成了100

所以,再查询a[0]的值的时候,值自然变成了100

float 与 double

Java 不能隐式执行向下转型,因为这会使得精度降低。

1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。Java 不能隐式执行向下转型,因为这会使得精度降低。

// float f = 1.1;

1.1f 字面量才是 float 类型。

float f = 1.1f;
隐式类型转换

因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。

short s1 = 1;
// s1 = s1 + 1;

但是使用 += 运算符可以执行隐式类型转换。

s1 += 1;

上面的语句相当于将 s1 + 1 的计算结果进行了向下转型:

s1 = (short) (s1 + 1);
switch

从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。

String s = "a";
switch (s) {
    case "a":
        System.out.println("aaa");
        break;
    case "b":
        System.out.println("bbb");
        break;
}

switch 不支持 long,是因为 switch 的设计初衷是对那些只有少数的几个值进行等值判断,如果值过于复杂,那么还是用 if 比较合适。

            System.out.println(a[0]);
    }
    public static void change(int[] a ){
            a[0]=100;
    }

}


结果:1 100

[外链图片转存中...(img-8CIyR7I1-1617635609089)]

由于引用传递,传递的是地址,方法改变的都是同一个地址中的值,

原来a[0]指向0x13地址,值是1,

后来在a[0] 指向的也是0x13地址,将值变成了100

所以,再查询a[0]的值的时候,值自然变成了100



#### float 与 double

Java 不能隐式执行向下转型,因为这会使得精度降低。

1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。Java 不能隐式执行向下转型,因为这会使得精度降低。

```java
// float f = 1.1;

1.1f 字面量才是 float 类型。

float f = 1.1f;
隐式类型转换

因为字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型。

short s1 = 1;
// s1 = s1 + 1;

但是使用 += 运算符可以执行隐式类型转换。

s1 += 1;

上面的语句相当于将 s1 + 1 的计算结果进行了向下转型:

s1 = (short) (s1 + 1);
switch

从 Java 7 开始,可以在 switch 条件判断语句中使用 String 对象。

String s = "a";
switch (s) {
    case "a":
        System.out.println("aaa");
        break;
    case "b":
        System.out.println("bbb");
        break;
}

switch 不支持 long,是因为 switch 的设计初衷是对那些只有少数的几个值进行等值判断,如果值过于复杂,那么还是用 if 比较合适。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值