JAVA基础(学自尚硅谷)

数据类型之变量

整数类型

Bit:在计算机中,数据的最小单位是位,位是指一位二进制数,英文名称是Bit。也称比特,1位信息只能表示2个状态(0或1)中的1个
Byte:字节,记为Byte或B,是计算机中信息的基本单位,表示8个二进制数位
所以1KB=1024Byte,1Byte=1024Bit
整数类型表数范围由bit位来决定,1byte=8位bit,1位bit可以表示0或者1,8位bit可以表示00000000到01111111(第一位是0表示正数,是1表示负数),也就是说1byte可以用8位bit表示就有2的8次方也就是256种可能,又因为Java规定,要从-128开始表示范围,所以byte在Java种可以表示-128到127这256位。
在Java中如果定义byte类型小于-128或者大于127会出错。
定义long类型时,变量后必须加"l"或者"L"
在这里插入图片描述

浮点型

定义float类型时,变量后必须加"f"或者"F",通常定义浮点型都是用double
在这里插入图片描述

字符型char(1字符=2字节)

char内部智能写一个字符,写多了会报错,char通常都有三种用法:1.声明一个字符。2.声明一个转义字符。3.使用Unicode值来表示字符型常量
在这里插入图片描述

布尔类型

布尔类型只表示true或者false,无关字节与字符
tips:如果想在字符串中使用双引号,可以用"代表
在这里插入图片描述

自动类型转换

小范围的变量类型转换为大范围的变量类型可以编译通过,反之不可以。
byte和char和short之间运算时,结果必须为int型
在这里插入图片描述
在这里插入图片描述
下图中的s2和b2如果用int来接的话就编译通过
在这里插入图片描述

强制类型转化

通过强制类型转换,可以把高精度的类型转换为低精度的类型,但是有可能损失精度
在这里插入图片描述

特殊编码情况

浮点类型操作时,默认类型是double类型
在这里插入图片描述

位运算符

在这里插入图片描述

数组

数组是在空间上是连续的,不像链表一样,通过指针连续,数组的长度是不可变的,当前的数组如果长度不够用了智能生成一个新的数组,把旧数组的数据放入新数组使用。
在这里插入图片描述

数组的用法

数组初始化:1.静态初始化(初始化和赋值同时进行)2.动态初始化(只初始化长度不赋值)
在这里插入图片描述
在这里插入图片描述

数组元素的默认初始值

当初始化一个数组并不给数组赋值时,数组元素的数据如下
在这里插入图片描述

二维数组的初始化

在这里插入图片描述

二维数组的存储结构

在这里插入图片描述

二维数组的长度与遍历

在这里插入图片描述

二维数组的内存结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法

局部变量与属性(全局变量)

局部变量不能定义修饰符,其修饰符等同于方法定义的修饰符。属性(全局变量)可定义可不定义,不定义默认为缺省(default)
局部变量在初始化时一定要定义初始值。属性(全局变量)不用,因为全局变量有默认值
在这里插入图片描述
在这里插入图片描述

方法的重载与重写

在这里插入图片描述
相同点:方法名都一样

不同点:
重写:子类继承父类重写方法,参数与返回类型必须一致,修饰符,异常返回值可以不一致
重载:同个类中同名不同功能方法,参数必须不一致,其他可以一致
重写的修饰符不能比父类的修饰符范围更小,比如父类是public,子类是private。道理参考Object的hashCode方法,假如A重写hashcode方法,修饰符为private,则B类继承A类,B类就没有hashcode方法了
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可变形参

在这里插入图片描述
使用方法如下
在这里插入图片描述

值传递

传值:把数据从一个变量赋值到另一个变量(包括String、Integer、Double等immutable类型,因为类的变量设为final属性)

// 基本数据类型
public class ParamChangeValue {    
    public static void main(String[] args) {        
        int s = 1;        
        System.out.println("args = [" + s + "]"); //输出1    
        change(s);        
        System.out.println("args = [" + s + "]");  //输出1,传递值不传递地址
    }    
    private static void change(int i){ 
        i = i* 5;    
    }
}

传引用:把地址从一个变量赋值到另一个变量,形参和实参指向同一个内存地址

// 引用数据类型
public class ObjectChangeValue {    
    public static class Score{        
        private int value; 
        public int getValue()  {            
            return value;  
        }  
        public void setValue(int value) {
            this.value = value;     
        }    
    } 
    
    public static void main(String[] args) {       
        Score score = new Score();        
        score.setValue(1);        
        System.out.println(score.getValue());//输出1            
        change(score);        
        System.out.println(score.getValue());//输出2,传递的是对象的地址   
    }    
   
    private static void change(Score score){  
        score.setValue(2);    
    }
}

println的用法

在这里插入图片描述
是因为println的方法重载了,有多种
在这里插入图片描述

四种修饰符

在这里插入图片描述
如下图结构中:如果com.atguigu.java包下的Order.java类的修饰符为缺省(default)的话,com.atguigu.java1包下的OrderTest.java就无法调用Order.java而com.atguigu.java包下的类就可以调用Order.java。这就是缺省的含义,只有同一个包下的类才能调用
在这里插入图片描述
如下图结构中:SubOrder继承Order,Order有个属性orderProtected是protected类型的,subOrder属于不同包下的子类(可以访问protected),OrderTest属于不同包下的非子类(不可访问protected)。
在这里插入图片描述
在这里插入图片描述

构造器的概念

1.构造器可以有多个,成为构造器的重载 2.如果没有自己写空参构造方法的话,系统会默认提供一个空参构造方法,如果自己写了一个构造器(不管带不带参数),系统则不会提供默认空参构造器
在这里插入图片描述

继承的概念

假如父类有一个私有属性,子类不可以直接调用父类的私有属性,但是可以调用父类的get/set方法
在这里插入图片描述
一个子类只能有一个父类,一个父类可以有多个子类,父类也可以继承另外一个类
所有的类都直接或者间接的继承于Object类
在这里插入图片描述

super关键字

当一个类继承另一个类时,若他们有相同的属性,则子类调用相同名字的属性时,如果不带super则默认表示调用本类的属性而不是父类的属性
在这里插入图片描述
当一个类继承另一个类时,子类如果在构造器中没有写super(),则代码会默认在子类的构造器中生成一个super(),在类的构造器中,this(形参列表)和super(形参列表)只能有一个
在这里插入图片描述

类初始的执行顺序

在这里插入图片描述
在这里插入图片描述

class A {
    private static int numA;
    private int numA2;

    static {
        System.out.println("A的静态字段 : " + numA);
        System.out.println("A的静态代码块");
    }

    {
        System.out.println("A的成员变量  : " + numA2);
        System.out.println("A的非静态代码块");
    }

    //如果注释了父类的无参构造器,则子类必须指定父类的构造器
//    public A() {
//        System.out.println("A的构造器");
//    }

    public A(int n) {
        System.out.println("A的有参构造");
        this.numA2 = n;
    }
}

class B extends A {
    private static int numB;
    private int numB2;

    static {
        System.out.println("B的静态字段 : " + numB);
        System.out.println("B的静态代码块");
    }

    {
        System.out.println("B的成员变量 : " + numB2);
        System.out.println("B的非静态代码块");
    }

    public B() {
        //如果父类没有无参构造,则在子类构造器需要显示调用父类构造器
        //若父类有无参构造,则可以不用显示调用super构造器
        super(1);
        System.out.println("B的构造器");
    }

    public B(int n) {
        //如果父类没有无参构造,则在子类构造器需要显示调用父类构造器
        //若父类有无参构造,则可以不用显示调用super构造器
        super(1);
        System.out.println("B的有参构造");
        this.numB2 = n;
    }
}

public class ClassLoad {
    public static void main(String[] args) {
        B anotherB = new B(1);// 思考有参构造的输出结果
    }
}

多态的概念

简单理解就是:一个电器,可以多态为冰箱,电视,电灯。
所谓虚拟方法调用:多个子类都有一个共用的方法,这个方法是继承于父类的,在编译期只能使用父类来调用这个方法,但是实际执行的时候调用的是子类的方法。
在这里插入图片描述

equals与==的区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自动装箱与拆箱

在这里插入图片描述

包装类

包装类是为了适应某些方法,某些方法的参数是Object类型,如果使用基本数据类型没法当成参数,如果把基本数据类型包装成引用数据类型后,就可以使用了
在这里插入图片描述
1为false是因为i和j都是new出来的,所以i和j的地址不相同,==在比较引用类型时比较的是地址,所以i不等于j。
2为true是因为n和m不是new出来的,是字面量的这种形式,在下图的cache[]中,存储了-128到127总共256个数字的数组,字面量这种行式只要是在-128到127之间的可以直接从cache中取,地址值都是一样的
3为false是因为x和y不在cache[]中,需要new出来,new出来地址就不一样了,会导致比较地址不一致出错。
在这里插入图片描述

static概念

Static只能修饰内部类!!!普通类不能用static修饰!!!
static可以用于描述一个类公共使用的部分,比如定义一个chinaPeople类表示中国人,有个属性叫country国家,每个对象的country都是中国,可以用static来定义

被static修饰的变量也叫类变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

单例模式

应用场景

1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件 
2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~ 
3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。 
4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。 
5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。 
6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。 
7. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。 
8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。 
9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。 
10. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.

最佳懒汉模式

public class Lazy {
    private String name;
    //不管初始化多少个该类的对象
    //设置和获取Name属性的值都是一样的
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //懒汉模式是只有调用getInstance()方法时才会创建一个该类的实例
    //原本不是线程安全的,但是加了synchronized锁和if判断后
    //当需要实例化时,会先判断当前是否有该类的实例化
    //如果没有则创建,如果有则返回静态的实例化,所以
    //优点:线程安全,不占内存
    private static Lazy lazy=null;
    private Lazy(){}
    public static Lazy getInstance(){
        if(lazy==null){
            synchronized (Lazy.class){
                lazy=new Lazy();
            }
        }
        return lazy;
    }
}

普通饿汉模式

public class Hungry {
    private String name;
    //不管初始化多少个该类的对象
    //设置和获取Name属性的值都是一样的
   public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //饿汉模式,一开始初始化时就已经开辟了一段内存
    //因为多次初始化也都是该类的同一个对象所以
    //优点:线程安全。缺点:站内存
    private static Hungry hungry=new Hungry();
    private Hungry(){}
    public static Hungry getHungry(){
        return hungry;
    }
    @Override
    public String toString() {
        return "Hungry{" +
                "name='" + name + '\'' +
                '}';
    }
}

代码块

如果说static是用来初始化类的话,那么代码块就是来初始化对象的,static在类的加载后执行,代码块在对象的加载后执行
在这里插入图片描述

final关键字

final可以用在显式初始化,代码块,构造器中。
final在形参中使用时不可变,意思是调用带final常量的方法时,此方法内部不可对final常量再赋值
在这里插入图片描述
return ++x错误,因为final作为形参时在方法内部不可变。return x+1正确,因为x并没有发生变化
o.i++正确,因为o并没有变,只是o内部的属性变化,o内部的属性不是final。o=new Other()不对,因为o发生变化了
在这里插入图片描述

抽象类与抽象方法(重要)

接口与抽象类异同

相同点:都不能实例化,都需要被继承(实现)
不同点:抽象类除了不能被实例化,其他与普通类没有任何差别。接口不是一种类。抽象类可以有构造器,接口不可以有构造器。抽象类可以有protected,default,public修饰符,接口只能是public修饰符。接口定义变量时自动是static final(全局变量),抽象类定义变量时是非static final(普通变量)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
抽象类的匿名子类,下面这个Person是个抽象类
在这里插入图片描述

接口

一个类不能实现多个父类,但可以继承多个接口
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代理模式代码

/**
 * 代理模式
 */
public class Proxy {
    public static void main(String[] args) {
        //被代理类
        Server server = new Server();
        //被代理类传入代理类中
        ProxyServer proxyServer = new ProxyServer(server);
        //代理类去做事
        proxyServer.network();
    }
}
//功能
interface Brower{
    void network();
}
//被代理类
class Server implements Brower{
    @Override
    public void network() {
        System.out.println("上网");
    }
}
//代理类
class ProxyServer implements Brower{
    private Brower brower;

    public ProxyServer(Brower brower) {
        this.brower = brower;
    }

    @Override
    public void network() {
        System.out.println("上网前检查");
        brower.network();
    }
}

简单工厂模式

汽车在CarFactory类中被生产出来,只需要调用CarFactory的getCar方法,传入要生产的车辆的名称即可生产对应的车辆。
简单工厂模式的缺点:如果引入了新的产品,则必须修改现有的代码,违背开闭原则(对于扩展开放,对于修改封闭)

public class SimpleFactory {
    public static void main(String[] args) {
        CarFactory.getCar("奥迪");
        CarFactory.getCar("比亚迪");
    }
}
class Car{
}
class Audi extends Car{
    public Audi() {
        System.out.println("奥迪被生产出来");
    }
}
class Byd extends Car{
    public Byd() {
        System.out.println("比亚迪被生产出来");
    }
}
//通用的工厂,一个工厂可以生产各种车
class CarFactory{
    public static Car getCar(String type) {
        if(type.equals("奥迪")){
            return new Audi();
        }else if(type.equals("比亚迪")){
            return new Byd();
        }else{
            return null;
        }
    }
}

普通工厂模式

加粗样式

public class CommenFactory {
    public static void main(String[] args) {
        AudoProxy audoProxy = new AudoProxy();
        audoProxy.productCar();
        BydProxy bydProxy = new BydProxy();
        bydProxy.productCar();
    }
}

class Car{
}
class Audi extends Car{
    public Audi() {
        System.out.println("奥迪被生产出来");
    }
}
class Byd extends Car{
    public Byd() {
        System.out.println("比亚迪被生产出来");
    }
}
//工厂接口
interface InterCar{
    Car productCar();
}
//奥迪工厂接口
class AudoProxy implements InterCar{
    @Override
    public Car productCar() {
        return new Audi();
    }
}
//比亚迪工厂接口
class BydProxy implements InterCar{
    @Override
    public Car productCar() {
        return new Byd();
    }
}

接口的面试题

下面的pX方法中,System.out.println(x)会报错,Java识别不出来x要调用接口A还是父类B。
可以改成System.out.println(A.x)和System.out.println(super.x)
但是接口和类中如果有同名同参数的方法时,子类在没有重写此方法的情况下,调用的是父类的方法而不是接口方法(类优先原则)
在这里插入图片描述
下面的代码中,play方法即重写了Playable也重写了Bounceable,Ball在接口中声明后就是public static final的,在实现类中就不可以再次new了
在这里插入图片描述

Java8下的接口新特性

在这里插入图片描述
如果子类继承了父类还实现了接口,子类想调用接口的方法就要用:接口.super.方法
在这里插入图片描述

内部类

在这里插入图片描述
在这里插入图片描述
在内部类中调用参数
在这里插入图片描述

异常

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
try catch基本使用

  try {
            String a="abc";
            Integer.parseInt(a);
            //1.catch (Exception e)作为父类异常不能放在最前面,除非只用Exception捕获
            //如果catch (Exception e)前面还有catch语句会报错
        }catch (NumberFormatException e){
            //2.一般打印异常信息使用e.printStackTrace();
            //System.out.println(e);
            //e.printStackTrace();
        }catch (Exception e){
            //3.这里不会执行,因为上一个catch已经捕获异常,后面的catch就不会处理
            e.printStackTrace();
        }
        //4.使用try catch捕获后,try catch后面的代码还会执行
        System.out.println("会执行");

finally的基本使用
在这里插入图片描述
在这里插入图片描述
throws+异常类型
在这里插入图片描述
throw运行后,后面的代码还会继续运行吗
throw异常后只是try-catch终止,后面的代码还要继续执行,

因为你加了try-catch,所以后面的代码还要继续执行,

不加try-catch,代码就执行不了了
如何自定义异常类
在这里插入图片描述
finally会比throw先执行
在这里插入图片描述
在这里插入图片描述
异常总结
在这里插入图片描述

集合

list

在这里插入图片描述
list小面试题
list.remove(2)删除的是索引为2的数据,list.remove(new Integer(2))删除的是数据为2的数据
在这里插入图片描述

IO流

File类的基本用法在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

IO流

在这里插入图片描述

在这里插入图片描述
比较重要的几个流
在这里插入图片描述
在这里插入图片描述

字符流

输入流FileReader的简单使用
先在工程或者module下创建一个文本文件hello.txt

 FileReader fr = null;
        try {
            //1.操作哪个文件
            File file = new File("hello.txt");
            //2.使用哪个流读取文件
            fr = new FileReader(file);
            //3.读取文件内容
            int data;
            while ((data=fr.read())!=-1){
                System.out.print((char)data);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            //4.关闭流
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

输入流FileReader批量读取数据

 File file = new File("hello.txt");
        FileReader reader = new FileReader(file);
        char[] data=new char[7];
        int len;
        while ((len=reader.read(data))!=-1){
            //1.第一种写法
            for (int i = 0; i < len; i++) {
                System.out.print(data[i]);
            }
            //2.第二种写法
//            String s = new String(data, 0, len);
//            System.out.print(s);
        }
        reader.close();

输出流FileWriter的基本使用

File file = new File("hello1.txt");
        //假如file文件已经存在,则不做追加操作,再创建一个新的文件
		//FileWriter writer = new FileWriter(file,false);
        //假如file文件已经存在,追加内容,不创建新文件
        FileWriter writer = new FileWriter(file,false);
        writer.write("i hava a dream \n");
        writer.write("yes");
        writer.close();

字节流FileInputStream与FileOutputStream的基本使用

  File file=null;
        File file1=null;
        FileInputStream inputStream=null;
        FileOutputStream outputStream=null;
        try {
            file = new File("logo.png");
            file1 = new File("logo2.png");
            inputStream = new FileInputStream(file);
            outputStream = new FileOutputStream(file1);
            int len;
            byte[] bytes = new byte[5];
            while ((len=inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
            }
            System.out.println("复制成功");
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

小总结:操作文本文件时,用字符流比较好。操作非文本文件时,用字节流比较好。如果需要复制,则使用字节流
缓冲字节流BufferStream的使用

 File file=null;
        File file1=null;
        FileInputStream inputStream=null;
        FileOutputStream outputStream=null;
        BufferedInputStream bufferedInputStream=null;
        BufferedOutputStream bufferedOutputStream=null;
        try {
            file = new File("logo.png");
            file1 = new File("logo2.png");
            inputStream = new FileInputStream(file);
            outputStream = new FileOutputStream(file1);
             bufferedInputStream = new BufferedInputStream(inputStream);
             bufferedOutputStream = new BufferedOutputStream(outputStream);
            int len;
            byte[] bytes = new byte[5];
            while ((len=bufferedInputStream.read(bytes))!=-1){
                bufferedOutputStream.write(bytes,0,len);
            }
            System.out.println("复制成功");
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                bufferedInputStream.close();
                bufferedOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

byte数据转成文件放到某路径下

 /**
     * 将byte数据存为文件
     */
    public static File getFileFromBytes(byte[] b,String path) {
        BufferedOutputStream stream = null;
        File file = null;
        try {
            file = new File(path);
            FileOutputStream fstream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fstream);
            stream.write(b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return file;
    }

在这里插入图片描述
图片加密与解密

FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream("logo.png");
            outputStream = new FileOutputStream("logo_secret.png");
            int len;
            byte[] bytes = new byte[20];
            while ((len=inputStream.read(bytes))!=-1){
                for (int i = 0; i < len; i++) {
                    //加密是字节进行^5操作
                    //解密是加密后的字节进行^5操作
                    //因为m^n^n后的结果还是m
                    outputStream.write(bytes[i]^5);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

记录文本中某个字符出现了多少次

 FileReader fileReader =null;
        try {
            fileReader = new FileReader("hello.txt");
            int len;
            char[] chars = new char[10];
            HashMap<Character, Integer> map = new HashMap<>();
            while ((len=fileReader.read(chars))!=-1){
                for (char c : chars) {
                    if(map.containsKey(c)){
                        map.put(c,map.get(c)+1);
                    }else{
                        map.put(c,1);
                    }
                }
            }
            for (Character character : map.keySet()) {
                System.out.print(character+"出现了");
                System.out.println(map.get(character)+"次");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            fileReader.close();
        }
转换流

在这里插入图片描述
使用转换流InputStreamReader读取数据到控制台

  InputStreamReader reader = new InputStreamReader(new FileInputStream("hello.txt"));
        int len;
        char[] chars = new char[20];
        while ((len=reader.read(chars))!=-1){
            String s = new String(chars, 0, len);
            System.out.println(s);
        }
        reader.close();

使用转换流复制文本文件以特定的字符集格式

  InputStreamReader reader = new InputStreamReader(new FileInputStream("hello.txt"));
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("hello_gbk.txt"),"gbk");
        int len;
        char[] chars = new char[20];
        while ((len=reader.read(chars))!=-1){
            writer.write(chars,0,len);
        }
        reader.close();
        writer.close();

对象流

在这里插入图片描述
在这里插入图片描述
使用对象流序列化数据
序列化不能处理static和transient修饰的属性
在这里插入图片描述
在这里插入图片描述
使用对象流反序列化数据
在这里插入图片描述

NIO

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网络编程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对象中的HashCode与equals

不重写HashCode,则对象获取的hashcode值是对象内存地址的hash值(两个属性值相等的对象由于通过两次new所以地址不会一样)而不是对象属性值的hash值

不重写equals,则对象在对比过程中,对比的是内存地址而不是对象属性值

hashcode规则:

hashcode相同时,两个对象不一定相同 (equals不一定相同)
hashcode不相同时,两个对象一定不等(equals不能相同)
两个对象相同时,hashcode一定相同(对象属性值都一样了,属性值的hash码一定要一样)
两个对象不相同时,hashcode不一定不相同(不同属性值的hash码可能一致)

重写equals作用在于对比属性值而不是内存值,重写hashcode作用体现在集合中,如hashmap:

有Person类,属性值有name,此时Person person=new Person(“张三”),map.put(person,学号),然后再
Person person2=new Person(“张三”),此时若Person类不重写hashcode方法,则map.get(person2)就无法获得学号。

String三个特性

*1.String被定义为final,说明不可被继承

  • 2.String内部使用char[]数组来存储数据
  • 3.String实现了comparable接口表明可以比较大小,实现Serializable接口表明可以序列化。
public class MainString1 {
    public static void main(String[] args) {
        /**
         * 1.String被定义为final,说明不可被继承
         * 2.String内部使用char[]数组来存储数据
         * 3.String内部存储数据的char[]被定义为finlal,数据有着不可变性
         * 4.String实现了comparable接口表明可以比较大小,实现Serializable接口表明可以序列化。
         */
        //1.1证明String被定义final不可变性
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);//true,说明s1和s2用的是同一个内存
        //1.2 证明String修改字符会重新生成新的
        s2+="def";
        System.out.println(s1);//还是指向abc的内存
        System.out.println(s2);//abcdef,开辟了新的内存
        s2.replace("a","a1");
        System.out.println(s1);//还是指向abc的内存
        System.out.println(s2);//a1bcdef,开辟了新的内存
        int i=3;
        MainString1 mainString1 = new MainString1();
        mainString1.change(i);
        System.out.println(i);
    }
    public void change(int i){
        i=2;
    }
    class Person{
        private String name;

        public Person(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }


        @Override
        public int hashCode() {
            return name != null ? name.hashCode() : 0;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    @Test
    public void test2(){
        /**
         * string的实例化方式
         * 1.通过字面量方式
         * 2.通过new+构造器
         *
         * 面试题:String xxx=new String("xx");在内存中创建了几个对象
         * 两个:一个是堆内存空间中的new结构,一个是char[]对应常量池的数据"xx"
         */
        //通过字面量的方式,s1和s2的数据指向了方法区中字符串常量池中
        String s1="abc";
        String s2="abc";
        //通过new+构造器,s3和s4的数据指向了堆空间中两个分开的对象,各自对应一个
        String s3 = new String("def");
        String s4 = new String("def");
        System.out.println(s3==s4);//false,因为s3和s4指向的不是同一个对象,虽然他们两个指向的对象的数据一样
        //
        Person s5 = new Person("ghi");
        Person s6 = new Person("ghi");
        System.out.println(s5.name==s6.name);//true,虽然他们不是同一对象的name属性,但是由于是字面量赋值,所以指向的同一个数据
        System.out.println(s5==s6);
        System.out.println(s5.equals(s6));
    }
    @Test
    public void test3(){
        String s1="abc";
        String s3="abc"+"def";
        String s4=s1+"def";
        String s5="abcdef";
        String s6=(s1+"def").intern();
        System.out.println(s3==s5);//true,没有使用到变量所以还是使用字面量
        System.out.println(s4==s5);//false,使用到了变量所以要重新生成一个对象
        System.out.println(s4==s6);//true,使用了intern返回的是字符串常量池的内容
    }
}

String常用方法

public class StringMethod1 {
    public static void main(String[] args) {
        String s1=" hello world ";
        System.out.println(s1.length());//int length(),返回字符串的长度
        System.out.println(s1.charAt(1));//char charAt(int index),返回某索引处的字符
        System.out.println(s1.isEmpty());//boolean isEmpty(),判断是不是空字符串
        System.out.println(s1.toLowerCase());//将所有字符串转换为小写
        System.out.println(s1.toUpperCase());//将所有字符串转换为大写
        System.out.println(s1.trim());//返回去除前后空格的副本,中间空格不会去除
        System.out.println(s1.equals("hello world"));//比较字符串是否相等
        System.out.println(s1.equalsIgnoreCase("hello world"));//不区分大小写,比较字符串是否相等
        System.out.println(s1.concat("lcy"));//将指定字符串拼接到此字符串结尾,等价"+"
        System.out.println(s1.compareTo("hello word"));//比较两字符串大小,负数表明前一个小
        System.out.println(s1.substring(1));//截取新字符串,从参数位置截取到最后
        System.out.println(s1.substring(1, 5));//截取新字符串,从第一个参数位置到第二个参数位置,第二个参数位置不包括在内,左闭右开
        System.out.println(s1.endsWith("ld "));//判断是否以参数结尾,空格也算
        System.out.println(s1.startsWith(" "));//判断是否以参数开头,空格也算
        System.out.println(s1.startsWith("h", 1));//判断第一个参数是否是第二个参数开始的开头,空格也算
        System.out.println(s1.contains("ld"));//判断字符串是否包含参数
        System.out.println(s1.indexOf("ld"));//返回指定子字符串在此字符串第一次出现的索引位置,未找到为-1
        System.out.println(s1.indexOf("ld", 1));//从第二个参数开始,返回指定字符串第一次出现的位置,未找到为-1
        System.out.println(s1.lastIndexOf("ld"));//返回指定字符串从右边开始数的第一次索引,未找到为-1
    }
}

StringBuffer与StringBuilder

StringBuffer线程安全效率低
StringBuilder线程不安全效率高
两者初始化时默认容量为16,可以自定义大小
当要加数据时发现容量不够了会扩容,扩容机制((<<1)+1,就是两倍加一)。如果我们预知字符串经常追加数据,可以在初始化的时候,给一个较大的值。

两道简单题

public class StringQuestion {
    public static void main(String[] args) {
        StringQuestion question = new StringQuestion();
        String str="abcdefg";
        System.out.println(question.reserve(str, 1, 3));
        String str1="abasdwqrcasababab";
        String str2="ab";
        System.out.println(question.getNum(str1, str2));
    }
    /**
     * 给定一个字符串,将其指定位置的数据进行翻转,比如"abcdefg"改成"abedcfg";
     * 思路,定义两个值,分别代表要反转数据的开头与结尾,两者循环互相换数据
     */
    public String reserve(String str,int startIndex,int endIndex){
        char[] chars = str.toCharArray();
        for (int x=startIndex, y=endIndex;x!=y;x++,y--){
            char temp=chars[x];
            chars[x]=chars[y];
            chars[y]=temp;
        }
        return Arrays.toString(chars);
    }
    /**
     * 给定一个字符串,获取指定字符串在此字符串出现的次数。
     * 比如"ab"在"abasdwqrcasab"出现的次数
     * 思路:使用indexOf判断是否有,如果有从有的位置往后找,循环这样
     */
    public int getNum(String str,String str2){
        int count=0,index=0;
        while ((index=str.indexOf(str2,index))!=-1){
            count++;
            index+=str2.length();
        }
        return count;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值