• My Notes(1)--JAVA基础


    Java简介

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

    面向对象程序设计(Object Oriented ProgrammingOOP)是一种计算机编程架构。OOP的一条基本原则是计算机程序由单个能够起到子程序作用的单元或对象组合而成。OOP达到了软件工程的三个主要目标:重用性、灵活性和扩展性。OOP=对象++继承+多态+消息,其中核心概念是类和对象。

    面向对象程序设计以对象为核心,该方法认为程序由一系列对象组成。类是对现实世界的抽象,包括表示静态属性的数据和对数据的操作,对象是类的实例化。对象间通过消息传递相互通信,来模拟现实世界中不同实体间的联系。在面向对象的程序设计中,对象是组成程序的基本模块

    面向对象编程语言主要有:JavaObjective-CC++PHPPython

    Java语言特点

    简单易学(Java语言的语法与C语言和C++语言很接近)

    面向对象(封装,继承,多态)

    平台无关性(Java虚拟机实现平台无关性)

    支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)

    支持多线程(多线程机制使应用程序在同一时间并行执行多项任)

    健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)

    安全性好

    JavaC++的区别

    都是面向对象的语言,都支持封装、继承和多态

    Java不提供指针来直接访问内存,程序内存更加安全

    Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多实现

    Java有自动内存管理机制,不需要程序员手动释放无用内存

    基础语法

    数据类型 

    基本数据类型

    数值型--整数类型(byte,short,int,long)浮点类型(float,double)字符型(char)布尔型(boolean)

    引用数据类型

    (class)接口(interface)数组([])枚举一种特殊的类

    Switch(expr)可以是哪些类型

    Java 5 以前,switch(expr)中,expr 只能是 byteshortcharint。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

    访问修饰符

    final 有什么用?

    用于修饰类、属性和方法;

    • final修饰的类不可以被继承
    • final修饰的方法不可以被重写
    • final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的

    final finally finalize区别

    • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表 示该变量是一个常量不能被重新赋值。
    • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块 中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
    • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调 用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的 最后判断。

    this关键字的用法

    this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

    this的用法在java中大体可以分为3种:

    1.普通的直接引用,this相当于是指向当前对象本身。

    2.形参与成员名字重名,用this来区分:

    3.引用本类的构造函数

    thissuper的区别

    • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
    • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
    • super()this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
    • super()this()均需放在构造方法内第一行。
    • 尽管可以用this调用一个构造器,但却不能调用两个。
    • thissuper不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
    • this()super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
    • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

    static关键字的用法

    static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

    static作用

    方便在没有创建对象的情况下来进行调用

    用来形成静态代码块以优化程序性能

    在类的首次加载的时候会去执行static的变量或者块,它是先于对象被加载的JVMstatic修饰的变量或方法块只加载一次和分配一次内存。

    静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的

    static成员变量(静态变量)的初始化顺序按照定义的顺序进行初始化。

    static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

    静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。

    static是不允许用来修饰局部变量

    static的加载过程

    1.首先找到main函数的入口,就是那个拥有main函数的类(判断一下该类是否有父类,如果有先加载父类)进行加载。

    2.加载完之后,去main函数中看看哪个类先进行初始化,然后去初始化这个类的成员变量之后再是它的构造函数(如果这个类有父类就要先初始化父类的成员变量和构造函数)

    3.类加载先于类初始化 没有出现过的类先会加载进来。

    普通类抽象类接口

    抽象类和接口的区别

    Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。

     

    普通类和抽象类的区别

    普通类不能包含抽象方法,抽象类可以包含抽象方法。

    抽象类不能直接实例化,普通类可以直接实例化。

    抽象类不能用final修饰,普通类可以

    Java中定义一个不做事且没有参数的构造方法的作用

    java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法,来帮助子类做初始化工作。

    重载(Overload)和重写(Override)的区别

    类方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

    重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

    重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。

    对象

    创建对象方法

    New 反射clone反序列化

    对象相等判断

     == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

     equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

    情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。

    情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)

    为什么重写equals时必须重写hashCode方法?

    当我们将equals方法重写后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值的约定。

    equals()重写规则

    自反性。对于任何非null的引用值xx.equals(x)应返回true

    对称性。对于任何非null的引用值xy,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true

    传递性。对于任何非null的引用值xyz,如果y.equals(x)返回truey.equals(z)返回true,那么x.equals(z)也应返回true

    一致性。对于任何非null的引用值xy,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false

    对于任何非空引用值xx.equal(null)应返回false

    hashCode()规则

    一个对象多次调用它的hashCode方法,应当返回相同的integer(哈希值)。

    两个对象如果通过equals方法判定为相等,那么就应当返回相同integer

    两个地址值不相等的对象调用hashCode方法不要求返回不相等的integer,但是要求拥有两个不相等integer的对象必须是不同对象。

      

    为什么 Java 中只有值传递

    按值调用(call by value)表示方法接收的是调用者提供的值按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。

    它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

    反射

    什么是反射机制?

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    静态编译和动态编译

    静态编译:在编译时确定类型,绑定对象

    动态编译:运行时确定类型,绑定对象

    反射机制优缺点

    优点: 运行期类型的判断,动态加载类,提高代码灵活度。

    缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

    反射机制的应用场景有哪些?

    反射是框架设计的灵魂。

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 SpringHibernate 等框架也大量使用到了反射机制。

    Java获取反射的三种方法

    1.通过new对象实现反射机制

    Student stu = new Student();

    Class classobj1 = stu.getClass();

    System.out.println(classobj1.getName());

    2.通过路径实现反射机制

    Class classobj2 = Class.forName("fanshe.Student"); System.out.println(classobj2.getName());

    3.通过类名实现反射机制

    Class classobj3 = Student.class;

    System.out.println(classobj3.getName());

    异常

    Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error Exception。其中 Error 类由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。Exception 分为两种:

    受检异常 :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;

    受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。

    不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。

    相反,受检查的异常必须要用 throws 语句在方法或者是构造函数上声明。

    throw与throws的比较

    1、throws出现在方法函数头;而throw出现在函数体。

    2、throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。

    3、两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

    常见的异常

    RuntimeException异常

    • ClassCastException(类转换异常)
    • IndexOutOfBoundsException(数组越界)
    • NullPointerException(空指针)
    • ArrayStoreException(数据存储异常,操作数组时类型不一致)
    • 还有IO操作的BufferOverflowException异常

    • ·  IllegalArgumentException - 传递非法参数异常。
      ·  ArithmeticException - 算术运算异常
      ·  ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
      ·  IndexOutOfBoundsException - 下标越界异常
      ·  NegativeArraySizeException - 创建一个大小为负数的数组错误异常
      ·        NumberFormatException - 数字格式异常
      ·  SecurityException - 安全异常
      ·  UnsupportedOperationException - 不支持的操作异常

    泛型

    在集合中存储对象并在使用前进行类型转换是很不方便的。泛型防止了那种情况的发生。它提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。

    泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。

    Array不支持泛型

    如果你把泛型和原始类型混合起来使用,Java 5的javac编译器会产生类型未检查的警告.作为一种类型的使用参数化的类型或数组类型,其元素类型是参数化类型的擦除,这种类型称为原始类型。原始类型是没有任何类型参数的泛型类或接口的名称

    原始类型的超类(分别是超接口)是对泛型类型的任何参数化的超类(超接口)的擦除。

    未从其超类或超接口继承的原始类型C的构造函数,实例方法或非static字段的类型为原始类型,该原始类型对应于在与C对应的通用声明中擦除其类型。

    原始类型与使用<?>作为类型参数有何不同?

    由于List<E>仅定义add(E) ,因此您不能仅将任意对象添加到List<?> 。 另一方面,由于原始类型List没有类型安全性,因此您几乎可以add任何内容add到List

    编译器做了出色的工作,可以保护您避免违反List<?>的类型不变性! 如果您已将参数声明为原始类型List ,则代码将编译,并且违反了List<String> names的类型不变式。

    String

    Java.lang中不能被继承的类

    public final class Boolean

    public final class Byte

    public final class Character

    public static final class Character.UnicodeBlock

    public final class Class<T>

    public final class Compile

    public final class Double

    public final class Float

    public final class Integer

    public final class Long

    public final class Math

    public final class ProcessBuilder

    public final class RuntimePermission

    public final class Short

    public final class StackTraceElement

    public final class StrictMath

    public final class String

    public final class StringBuffer

    public final class StringBuilder

    public final class System

    public final class Void

    在使用 HashMap 的时候,用 String key 有什么好处?

    HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

    StringStringBufferStringBuilder的区别是什么?String为什么是不可变的

    可变性

    String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilderStringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。

    线程安全性

    String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilderStringBuilderStringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacityappendinsertindexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

    性能

    每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

    对于三者使用的总结

    如果要操作少量的数据用 = String

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

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


    字符串反转

    /**
    
         * 利用栈的FILO实现反转
    
         **/
    
        public static String convertByStack(String s) {
    
            if (s == null || s.length() == 0) return s;
    
            Stack<Character> stringStack = new Stack<Character>();
    
            char[] array = s.toCharArray();
    
            for (Character c : array) {
    
                stringStack.push(c);
    
            }
    
     
    
            for (int i = 0; i < s.length(); i++) {
    
                array[i] = stringStack.pop();
    
            }
    
     
    
            return new String(array);
    
        }
    
     
    
        /**
    
         * 利用异或实现反转
    
         * 相同为0,不同为1
    
         * A^B = T
    
         * B^T = B^A^B = A^B^B = A^0= A
    
         * A^T = A^A^B = 0^B = B
    
         **/
    
        public static String convertByExor(String s) {
    
            if (s == null || s.length() == 0) return s;
    
            char[] array = s.toCharArray();
    
            int length = s.length() - 1;
    
            for (int i = 0; i < length; i++, length--) {
    
                array[i] ^= array[length];
    
                array[length] ^= array[i];
    
                array[i] ^= array[length];
    
            }
    
            return new String(array);
    
     
    
        }
    
     
    
        /**
    
         * 转换成char数组后遍历交换
    
         **/
    
        public static String convertByChar(String s) {
    
            if (s == null || s.length() == 0) return s;
    
            char[] array = s.toCharArray();
    
            int length = s.length() - 1;
    
            for (int i = 0; i < length; i++) {
    
                array[i] = s.charAt(length - i);
    
            }
    
            return new String(array);
    
        }
    
     
    
        /**
    
         * 转换成char数组后遍历交换进阶  速度是上面的两倍
    
         **/
    
        public static String convertByCharPlus(String s) {
    
            if (s == null || s.length() == 0) return s;
    
            char[] array = s.toCharArray();
    
            int length = s.length() - 1;
    
            for (int i = 0; i < length / 2; i++) {
    
                array[i] = s.charAt(length - i);
    
                array[length - i] = s.charAt(i);
    
            }
    
            return new String(array);
    
        }
    
     
    
        /**
    
         * 利用逆序遍历
    
         **/
    
        public static String convertByLoop(String s) {
    
            if (s == null || s.length() == 0) return s;
    
            StringBuilder sb = new StringBuilder();
    
            for (int i = s.length() - 1; i >= 0; i--) {
    
                sb.append(s.charAt(i));
    
            }
    
            return sb.toString();
    
        }
    
     
    
     
    
        /**
    
         * 递归实现反转
    
         **/
    
        public static String convertByRecursive(String s) {
    
            return s == null || s.length() <= 1 ? s : convertByRecursive(s.substring(1)) + s.charAt(0);
    
    }
    
     

    JDK 1.8使用到的新特性。

    lambda表达式

    stream

    LocalDate(摒弃了java.util.date)

    optional(解决NPE,并封装了一个类)

    Base64

    concurrentHashMap  

    parallel数组

    新的JVM--元空间

  • 相关阅读:
    大话设计模式--第六章 装饰模式
    大话设计模式--第五章 依赖倒置原则
    Linux—文件管理
    Linux—系统管理
    Mysql—添加用户并授权
    Linux—文件权限管理(chmod、chown、chgrp)
    Linux—管理用户、用户组及权限
    Mysql—修改用户密码(重置密码)
    Linux—编译安装详解
    Python—实现sftp客户端(连接远程服务器)
  • 原文地址:https://www.cnblogs.com/JackpotHan/p/14654122.html
Copyright © 2020-2023  润新知