Java大总结(二)—— 面向对象、常用类

一、面向对象

1. 什么是类、对象,类和对象的关系

类: 类是创建对象的模板

对象: 万物皆对象

2. 如何理解面向对象

对现实生活中的事物进行描述,用类进行描述,将事物的属性和行为用类的属性和方法进行体现

3. 什么是属性、什么是方法

属性:对象的特征

方法:对象的操作

4. 如何创建对象、创建对象的时候JVM做了什么事情

//使用new关键字创建对象
类名 对象名 = new 类名();//调用类的默认构造函数

虚拟机在遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程(具体过程这里不做详解)。在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定。,为对象分配空间的任务等同于把一块确定大小的的内存从java堆里划分出来。假设java堆里内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump the Pointer)。如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”。选择哪种分配方式由Java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

5. 构造函数、构造函数重载

构造函数: 给对象进行初始化,特点:函数名与类名相同、不用定义返回值类型、没有具体的返回值

构造函数重载: 在同一个类中定义多个构造函数,它们各自的参数表不同

6. 参数的传递:基本数据类型传递、引用数据类型传递

基本数据类型传递时数据的值在函数调用前后不发生变化

引用数据类型传递时该数据类型的地址不会发生变化,但数据的值会发送变化,比如数组各元素的值

7. 方法的声明

访问修饰符: 定义方法的权限,哪些位置可以使用

返回值类型: 该方法调用后传递一个什么类型的数据

方法名: 即方法的名称

形参: 是一个变量,用于存储调用函数时传递给函数的实际参数

实参: 传递给形参的具体数值

8. 方法的调用、属性的调用

创建类的一个对象,通过对象去调用方法和属性

对象名.方法名(参数表)/对象名.属性名

9. 方法重载

java允许在一个类中定义多个重名方法,但是各个方法的参数表必须不同(参数类型不同或者参数个数不同)

10. 封装

目的在在于保护数据,将设计者和使用者分开,通过private关键字实现

应用:Javabean

11. 继承

概念:子类继承于父类,可以继承父类的属性和方法

特征:支持单继承,不支持多继承

目的:提高了代码的复用性、让类与类之间产生了关系

12. 方法重写

指的是子类可以重写父类已经定义的方法

但是通过final修饰符修饰的方法不能被重写

13. 抽象类

概念:不具体的类,类中的方法没有方法体

和普通类的区别、特性

方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰,抽象方法必须定义在抽象类中,该类必须也被abstract修饰

抽象类不可以被实例化,调用抽象方法没意义

抽象类必须其子类覆盖所有的抽象方法后,该子类才可以被实例化,否则该子类还是抽象类

单继承

一个子类只能有一个直接父类

14. 抽象方法

概念:只有声明没有实现(方法体)

目的:重写

15. 接口

概念

意义:扩展

特征

  • Interface定义接口
  • 接口的方法都是抽象的
  • 接口里最常见定义全局常量(public static final)和抽象方法(public abstract),而且这些成员都有固定的修饰符
  • 接口中的成员都是公共的权限

接口和抽象类的区别(7个以上)

参数 抽象类 接口
默认的方法实现 它可以有默认的方法实现 接口完全是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器 抽象类可以有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 接口是完全不同的类型
访问修饰符 抽象方法可以有publicprotecteddefault这些修饰符 接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法 抽象方法可以有main方法并且我们可以运行它 接口没有main方法,因此我们不能运行它。(java8以后接口可以有default和static方法,所以可以运行main方法)
多继承 抽象方法可以继承一个类和实现多个接口 接口只可以继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。

16. 多态

多态的体现:

成员变量:编译看左边,运行看右边

构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化

成员方法:编译看左边,运行看右边(存在方法重写)

静态方法:编译看左边,运行看左边(静态和类相关,算不上重写,所以访问还是左边的)

多态的好处: 提高了代码的维护性、提高了代码的扩展型性

里氏代换原则: 一个软件实体如果使用的是基类的话, 那么也一定适用于其子类, 而且它根本觉察不错使用的是基类对象还是子类对象; 反过来的代换这是不成立的, 即: 如果一个软件实体使用一个类的子类对象,那么它不能够适用于基类对象。

17. 内部类

局部内部类

指内部类定义在方法体内,只能在该方法或条件的作用域内才能使用,退出这作用域就无法引用。

public class OuterCls {
    private String name;
    public String getName(){
        return name;
    }
 
    public void getInerCls(){
        class InerCls{
            private String name;
 
            public String getName(){
                return name;
            }
        }
    }
}

静态内部类

public class OuterClass {
    private String name;
 
    static class StaticInerCls{
        private String name;
    }
}

匿名内部类

为了免去给内部类命名,或者只想使用一次,就可以选择使用匿名内部类。

 public void countDown(){
      new Thread(){
          @Override
          public void run() {
 
          }
      }.start();
 }

普通内部类

public class OuterCls {
    private String name;
    public String getName(){
        return name;
    }
 
    class InerCls{
        private String name;
 
        public String getName(){
            return name;
        }
    }
 
}

18. 工厂模式(3种)

简单工厂模式

  • 工厂是一个简单的类,不是抽象类或者是接口,其中生成返回具体产品通常使用if-else或者swith-case。
  • 返回产品的方法一般都是static,所有也称之为静态工厂方法模式(Static FactoryMethod Pattern)。
  • 也可以认为:简单工厂模式看为工厂方法模式的一种特例,所以优缺点等介绍将不做,具体请看工厂方法模式。

工厂方法模式

  • 生成返回具体产品是通过实现抽象工厂类或者工厂接口方式。
  • 一组产品依赖实现一个抽象类或接口。
  • 一个工厂工具(工厂实现类)返回产品组中一个具体产品类。

Java大总结(二)—— 面向对象、常用类抽象工厂模式

  • 提供创建一组相关相互依赖对象的接口,而无需指定他们具体的类。
  • 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。
  • 抽象工厂实现类提供的产品可以为多个,这多个产品可以实现依赖于不同的产品接口或抽象类产品。

Java大总结(二)—— 面向对象、常用类

19. 访问控制符

public、private、protected、默认

Java大总结(二)—— 面向对象、常用类

static

  • 随着类的加载而加载
  • 优先于对象存在
  • 被类的所有对象共享
  • 可以通过类名调用

final

  • final修饰类:该类不能被继承
  • final修饰方法:该方法不能被重写
  • final修饰变量:该变量不能被重新赋值

this

  • 代表当前类的对象的引用,即代表当前类的一个对象

super

  • 代表父类的引用

instance of

  • instanceof运算符的前一个操作符是一个引用变量,后一个操作数通常是一个类(可以是接口),用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是返回true,否则返回false。

20. 异常处理

什么是异常

异常情形(exceptional condition)是指阻止当前方法或作用域继续执行的问题。

异常的分类

  • Error JAVA环境编译错误
  • Runtime Exception 运行处异常
  • Exception 标准Java库方法异常
  • throw 用户自定义异常

处理方法

抛出异常:要理解抛出异常,首先要明白什么是异常情形(exception condition),它是指阻止当前方法或作用域继续执行的问题。其次把异常情形和普通问题相区分,普通问题是指在当前环境下能得到足够的信息,总能处理这个错误。对于异常情形,已经无法继续下去了,因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境中跳出,并把问题提交给上一级环境,这就是抛出异常时所发生的事情。抛出异常后,会有几件事随之发生。首先,是像创建普通的java对象一样将使用new在堆上创建一个异常对象;然后,当前的执行路径(已经无法继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方继续执行程序,这个恰当的地方就是异常处理程序或者异常处理器,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。

捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

throw和throws的区别

throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws语句用在方法声明后面,表示抛出异常,由该方法的调用者来处理。

throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
throw是当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常是,具体向外抛异常的动作,所以它是抛出一个异常实例。

throw与throws的比较

  • throws出现在方法函数头;而throw出现在函数体。
  • throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
  • 两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

自定义异常

第一步,先自行定义异常处理的类

/**
 * 自定义异常处理的类
 * @author
 */
public class BankException extends Exception/*这里的继承不能少*/{
    void showMessage(){
        System.out.println("你输入的数据是异常的!");
    }
}

第二步,对这个类进行运用

public class Bank {
    /**
     * 在方法后面加 throws BankException因为错误可能不只有一个,谁调用这个方法,谁就接受这个异常
     * @param in
     * @param out
     * @throws BankException
     */
    void iocome( int in , int out ) throws BankException /*此处也可以抛出多个异常类*/{
        if (in < 0 || out > 0) {
            throw new BankException();
        }
        System.out.println("你的操作是正常的!");
    }
}

第三步,测试样例

public class Abnormal {
    public static void main(String args[]) {

        /**
         * 自定义异常
         */
        Bank bank = new Bank();
        try {
            bank.iocome(-100 , -50);
        } catch (BankException e) { // 在此处,不用系统的而是自己定义的异常处理类
            e.showMessage();
        }
    }
}

二、常用系统类

1. String、StringBuffer、StringBuilder

String常用方法

String str=new String("a");	//创建a字符串
str.length();	//字符串长度
str.charAt(int i);//第i个字符
str.indexOf(String p);	//p第一次出现的位置,没有则返回-1
str.indexOf(String p,inti);	//p在第i个字符后第一次出现的位置,没有则返回-1
str.concat(String t);	//将t附在字符串的末尾,也可用+号来连接
str.substring(int i,int j); //从i到j的子字符串
str.split(String a);	//把字符串以a字符分开,返回一个字符串数组
str.hashCode();	//哈希码
str.equals(String a);	//和a字符串进行比较是否相等

StringBuffer常用方法

StringBuffer strbf=new StringBuffer("exception");	//创建一个StringBuffer类的字符串
strbf.append(String s);//将指定的字符串追加到此字符序列。
strbf.reverse();		//将此字符序列用其反转形式取代。
strbf.delete(int start, int end);	//移除此序列的子字符串中的字符。
strbf.insert(int offset, int i);	//将 int 参数的字符串表示形式插入此序列中。
strbf.replace(int start, int end, String str);	//使用给定 String 中的字符替换此序列的子字符串中的字符。

String,StringBuffer,StringBuilder在JVM中的处理情况

在这三种情况下,String是执行最慢的。因为Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而对StringBuffer,StringBuilder操作则不许要重新创建和回收直接在其上面更改便可。反映到程序中就是String在改变后的哈希码会和之前完全不同,而StringBuffer,StringBuilder的哈希码依然一样。

线程安全

String为不可变类,在java中不可变类都是线程安全的,
StringBuffer也是线程安全的。但是是靠StringBuffer中的方法中的synchronized关键词来保持线程安全。
StringBuilder是线程不安全的。

2. Math

Math.E                          //自然常数e=2.7182818284590452354
Math.abs(12.3);                 //12.3 返回该值的绝对值  
Math.abs(-12.3);                //12.3  

Math.copySign(1.23, -12.3);     //-1.23,返回第一个参数的量值和第二个参数的符号  
Math.copySign(-12.3, 1.23);     //12.3  

Math.signum(x);                 //如果x大于0则返回1.0,小于0则返回-1.0,等于0则返回0  
Math.signum(12.3);              //1.0  
Math.signum(-12.3);             //-1.0  
Math.signum(0);                 //0.0  


//指数  
Math.exp(x);                    //e的x次幂  
Math.expm1(x);                  //e的x次幂 - 1  

Math.scalb(x, y);               //x*(2的y次幂)  
Math.scalb(12.3, 3);            //12.3*2³  

//取整  
Math.ceil(12.3);                //返回最近的且大于该值的整数13.0  
Math.ceil(-12.3);               //-12.0  

Math.floor(12.3);               //返回最近的且小于该值的整数12.0  
Math.floor(-12.3);              //-13.0  

//x和y平方和的二次方根  
Math.hypot(x, y);               //√(x²+y²)  

//返回该值的二次方根  
Math.sqrt(x);                   //√(x) x的二次方根  
Math.sqrt(9);                   //3.0  
Math.sqrt(16);                  //4.0  

//返回该值的立方根  
Math.cbrt(27.0);                //3   
Math.cbrt(-125.0);              //-5  

//对数函数  
Math.log(e);                    //1 以e为底的对数  
Math.log10(100);                //10 以10为底的对数  
Math.log1p(x);                  //Ln(x+ 1)  

//返回较大值和较小值  
Math.max(x, y);                 //返回x、y中较大的那个数  
Math.min(x, y);                 //返回x、y中较小的那个数  

//返回x的y次幂  
Math.pow(x, y);                   
Math.pow(2, 3);                 //即2³ 即返回:8  

//随机返回[0,1)之间的无符号double值  
Math.random();                    

//返回最接近该值的整数,如果居中,则取偶数  
Math.rint(12.3);                //12.0   
Math.rint(-12.3);               //-12.0  
Math.rint(78.9);                //79.0  
Math.rint(-78.9);               //-79.0  
Math.rint(34.5);                //34.0  
Math.rint(35.5);                //36.0  

Math.round(12.3);               //与rint相似,返回值为long  

//三角函数  
Math.sin(α);                    //sin(α)的值  
Math.cos(α);                    //cos(α)的值  
Math.tan(α);                    //tan(α)的值  

//求角  
Math.asin(x/z);                 //返回角度值[-π/2,π/2]  arc sin(x/z)  
Math.acos(y/z);                 //返回角度值[0~π]   arc cos(y/z)  
Math.atan(y/x);                 //返回角度值[-π/2,π/2]  
Math.atan2(y-y0, x-x0);         //同上,返回经过点(x,y)与原点的的直线和经过点(x0,y0)与原点的直线之间所成的夹角  

Math.sinh(x);                   //双曲正弦函数sinh(x)=(exp(x) - exp(-x)) / 2.0;  
Math.cosh(x);                   //双曲余弦函数cosh(x)=(exp(x) + exp(-x)) / 2.0;  
Math.tanh(x);                   //tanh(x) = sinh(x) / cosh(x);  

//角度弧度互换  
Math.toDegrees(angrad);         //角度转换成弧度,返回:angrad * 180d / PI  

Math.toRadians(angdeg);         //弧度转换成角度,返回:angdeg / 180d * PI  

3. Random

该类的构造方法
Random():构造一个无参的随机数生成器。使用系统时间的毫秒作为默认种子。
Random(long seed):使用long数据类型的种子构造一个随机数生成器。
方法摘要
boolean nextBoolean():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean值。
double nextDouble():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 double 值。
float nextFloat():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 float 值。
int nextInt():返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值.
int nextInt(int n):返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值n(不包括)之间均匀分布的 int 值。
long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
void setSeed(long seed):使用单个 long 种子设置此随机数生成器的种子。

注意

如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数

字序列。

4. Date、Calender

使用字符串初始化Date
String dateString = “2018-02-23”;
Date date= new SimpleDateFormat(“yyyy-MM-dd”).parse(dateString);
使用时间戳初始化
Date date = new Date(时间戳);
计算两个日期相差天数
long day = date1.getTime() - date2.getTime()) / (246060*1000) + 1;
使用Calendar
Calendar calendar=Calendar.getInstance();
Date date=calendar.getTime);
获取年月日
calendar.get(Calendar.YEAR);
alendar.get(Calendar.MONTH) + 1;
calendar.get(Calendar.DAY_OF_MONTH);
calendar.get()方法
calendar.get(Calendar.DAY_OF_WEEK); 当前周的第几天
calendar.get(Calendar.DAY_OF_MONTH); 当前月的第几天

calendar.get(Calendar.DAY_OF_YEAR); 当前年的第几天

5. Arrays

给数组赋值:通过fill方法。

对数组排序:通过sort方法,按升序

比 较 数 组: 通过equals方法比较数组中元素值是否相等。

查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。

截取数组元素:通过copyOf方法和copyOfRange对数组元素进行截取。

打印数组元素:通过toString方法打印数组元素。

将数组转换为list:通过asList方法转换为List。

6. System

System类提供了代表标准输入、标准输出和错误输出的类变量,并提供一些静态方法用于访问环境变量、系统属性的方法,还提供了加载文件和动态链接库的方法。