JAVA学习 面向对象

CPU处理复杂逻辑,GPU显卡处理简单逻辑。

二进制逢二进一,八进制逢八进一,十进制逢十进一,十六进制逢十六进一。

正数的原反补是本身,负数的原反补,反码是符号位不变,其他位趋反,补码是+1,计算机中负数是以补码的形式存储的,因为只有补码和绝对值相同的正数相加是0,数据溢出了达到相加是0的效果。

18进制转二进制、八进制都用短除法,倒着取余。18进制转10进制用科学表达式。

计算机中运算速度最快的三种运算
与运算是两个开关都闭合才能运行的串联电路。串联就是两个开关都在一条电路线上,要两个都闭合才能发亮。两个都为1,结果才为1,只要有一个0,结果就是0。
与是两个,两个都true,闭合,才亮。
或运算只要一个开关闭合就能运行的并联电路。并联就是两个开关,分成两条线和总线相连接,只要有一条线一个开关闭合就可以发亮。只要有一个1结果就是1,两个都是0结果就是0。
非运算是开关一闭合,就短路。趋反。
或是一个true,一个闭合,就亮。
异或运算就是相同为0,不同为1。

赋值long、float类型,数字要在后面加上L或F,以示和整型的区分。整型浮点型字节型数字的与或加减运算,类型不同范围不同,运算,数据会丢失,无法运算会报错。取值范围大的转取值范围小的需要强转类型。如果范围大的数没有超过类型范围小的位数,那么也不会出错。byte short int long float double

运行以后一堆乱码可能是编码格式不同。GBK/UTF-8

++i 先自增再打印。i++打印结束以后再自增。

布尔型的与或非运算用于条件判断:与两种都为true,执行什么代码,false否则else执行什么代码或不做操作。
或是满足一种条件为true就可以执行一段什么代码。
非连着不符合预期的情形执行什么代码,或者是循环。
双与短路运算符,一长串的条件判断只要判断过程中出现false,后续条件就不再继续判断,执行效率的问题。
企业里涉及钱的开发,使用float或double相加减会出现数据丢失的情况。

continue :结束此次循环,继续下次循环。
break:跳出循环。
死循环该有合适的退出机制。

引用数据类型如数组,存数组的首地址,指向堆中划分的,接连成片的内存空间。jvm会在运行时将栈中的符号引用转化为内存地址指向堆中的数据。

数组的定义相当于栈中的符号引用,初始化指的是new关键字和数组的长度在堆中分配内存空间,赋值指的是在堆中分配好的内存空间中按数组的下标存入数据。

写法上,数组的定义,写了数组的长度就不用写具体的数据了。数组的赋值上,数组的下标从0开始,对同一个下标再次赋值原来的数据会被覆盖掉。每个数组都有一个length属性,数组的长度-1就是数组的最大下标。int类型的数组只写长度数据默认是0,可以打印看看。

数组的越界异常:array index out of bounds exception.
数组被创建以后无法改变数组的长度,具体的内容在数组的扩容。
其他类型的数组被创建以后的默认值:int0 short0 byte0 float0.0 double0.0 char\u0000 boolean false String null

算法就是一段代码,操作有数据结构的数据。
for循环按下标遍历数组。
数组的查找、数组的反转,数组的打印,整合作业,数组的合并。
实际业务中查找比添加数据多。
冒泡排序、二分查找。

大O表示法:
时间复杂度:顺序查找时间是线性增长;按下标或余数存储的数据只需要一次就能找到是常数阶,冒泡排序只有剩下的一个不用冒其他的全部都要比较一遍开平方是指数阶,二次函数的图像;二分查找法对数函数开根号。横轴是数据量,纵轴是需要的时间。

空间复杂度:需要额外的空间是O(n),不需要额外的空间是O(1),需要两倍的空间是O(n方)。

二维数组是数组的数组,储存数组的地址,指向不同地址的内存空间。

杨辉三角实现

面向对象
封装
面向过程的语言是通过分析需求表达成函数一步步实现。
面向对象是通过对象去调用函数。
对象类型的数组的符号引用指向堆内存中数组里对象的首地址内存地址,每一个堆中对象的内存地址再指向每个对象在堆中其具体的属性数据。
基础数据类型占8个字节,引用数据(String)类型占4个字节。String类型的符号引用在程序运行时jvm把符号引用转化成内存地址的过程,叫直接引用。

函数的参数
函数括号里的参数叫形参,调用函数时传进去的参数叫实参,可以有多个参数,都用逗号隔开。

return
return的类型就是返回值的类型,没有返回值函数用void。可以通过接收到的返回值进行下一步的操作。return也有中止当前的方法继续执行的含义。

函数的重载
函数名不同,形参列表的数据类型或数量不同。
形参名不同、返回值不同无法实现函数的重载。调用方法可以不需要打印返回值,调用方法传入实参无关联形参的名字。

可变参数
可变参数只能出现一个,并且只能放在末尾。
settings. auto imports. add unambiguous imports on the fly.
optimize imports on the fly.自动引包
全限定名,全类名,全路径,都一样的。
编译后的JAVA文件从磁盘加载到内存,放到方法区中运行,方法区是内存的一片空间,字符串也是放在方法区里边。

JAVA字节码文件
out目录下有被编译后的JAVA文件。用插件打开JAVA的字节码文件。
看到ca fe ba be,就表示该文件是在JAVA虚拟机上运行的JAVA的字节码文件。
00 00 00 34,表示是JAVA的1.8版本号。
后面的是常量池,包含定义的字符串,类的名称。
然后是代码的指令,包含所有的代码,是jvm可以识别的指令,而不是计算机可以识别的指令。
每个类的方法都在方法区。
在不同的平台装上不同的jvm,这样JAVA就实现了跨平台。

构造器
每个实例对象属性的值存放在堆内存当中,但是所有的实例对象共用方法区的方法。
写了有参构造以后默认的无参构造消失,写有参构造的时候,最好把无参构造也补上。

this关键字:
所有的实例对象共用方法区的方法。栈中对象的符号引用指向堆中的实例对象,实例对象再指向方法区中字节码文件里的方法,this在方法中,this再指向调用方法的那个实例对象。
用this调用构造器只能放在构造器方法的第一行。

setter&getter
setter校验。getter过滤。这么做的原因是属性不具备多态性。对属性的操作最好使用setter和getter方法。

JAVA类的写法:属性、构造器、方法、setter和getter。
main方法要写在test类里。

String
string的空参构造赋值""。要用is Empty()/is Null() 判断有没有值。offset,数组的下标从第几位开始,length,读几位。
new创建的字符串储存在堆中。
""创建的字符串储存在常量池中。
等于等于 比较的是内存地址。
.equals()比较的是值。
.equalsIgnoreCase()忽略大小写比较值。
.toLowerCase() .toUpperCase()开辟了一片新的内存空间,已经不是原来的string,打印的是方法。
.indexOf() 是否包含字符串,返回的是下标。
.contain() 是否包含字符串,返回的是boolean值。
.charAt()输入下标,返回的是字符串。
.subString() 截取字符串,只包含第一个不包含第二个。
replaceAll() 替换。
基础数据类型==比较的是值。

Integer面试题
在integerCache常量池的缓存中,会储存integer-128到127的值,所以使用等于等于 判断这个区间的内存地址是否相等时返回值是ture。如果超出了这个范围,就需要去堆中,new创建一个,那么在使用==比较的时候,内存地址不同了,返回值就是false。
Integer包含int值和null值,查询的时候找不到可以返回null值。

类的权限修饰符:public private default protected

hashcode
特点
不能逆运算:不能由生成的固定长度的数字反推出传入的内容。
雪崩效应:原数据有一丁点改变生成的固定长度的数字都不一样。
强抗碰撞性:就算传入的内容很相似,生成的数字也不一样。

用途
注册时hash运算给密码散列以后保存在数据库中,登录时通过用户名取出hash运算以后的密码与散列了的刚刚输入的密码进行校验,一致则登录成功。
密码可以通过循环的方式暴力破解,越复杂越难破解。
利用雪崩效应文件校验。

hash算法:SHA1、SHA-256、SHA-512。

control n 搜索Object类 control f 搜索类里的方法

Object类的方法
hashcode():数组长度大于0,数组有值,遍历数组,乘以素数31再加上下一个值,返回得到的结果。用字符串调用hashcode(),得到的是可以算出来的一个值。
equals():先用==比较内存地址是否相等,如果相等,直接返回true。用instanceof判断是不是String类型的对象,把传入的对象强转成String,while循环比较char数组,一致返回true,不一致返回false。重写父类Object的equals(),把形参传进来的Object强转成this,比较以后返回布尔类型的值。

toString():重写toString()可以打印类的信息,直接打印对象出现的是类的全限定名称加内存地址。打印String是具体的字符串的原因是String类重写了toString()。alt insert 系统重写toString()。

clone():类实现Cloneable接口,方法返回Object类型,重写的方法内调用父类的clone(),使用时强转成被复制的类,该抛异常抛异常。
栈内存溢出StakeOverFlowException:方法自己调用自己。
浅拷贝,拷贝过来的属性的值不变,修改属性的值,被拷贝的对象的属性的值也会改变。

多态
子类继承父类,可以继承和重写父类的方法,可以把父类作为形参,传入子类对象,以子类为实现对象,以此来实现多态。

常量池中符号引用转化为内存地址的过程叫直接引用,在类加载或第一次使用时就可以被转化的,称为静态解析。在运行时转化的称为动态链接。
所以在类加载时就被转化的称为静态类型或编译类型、或声明类型、或外观类型。动态链接的称为动态类型、运行时类型、或者叫实际类型。
非虚方法invokeStatic invokeInterface invokeSpecial 静态方法,私有方法,实例构造器,被final修饰的方法,编译时的直接引用。invokeVirtual调用虚方法,实例的方法,有可能是父类的方法,也有可能是子类的方法,在运行时确定。

重载和多态的区别
有继承关系的类作为重载方法的参数,在调用方法时,只会实现传入父类的参数的方法,因为重载方法的实现类型是静态类型。多态是要在子类里重写才可以实现子类的方法。重载的方法由,函数名相同,函数的参数的类型不同,函数的参数的数量不同实现。要注意重载和多态的区别。
重载方法可以自动转型。根据函数名对参数自动转型。写几个承载方法,参数类型不同,一个个注释掉,可以发现。

静态解析和动态分派结合:
Animal dog =new Dog();
dog. eat (“meat”);
从字节码文件中可以看到Invoke special 静态解析父类,再去堆中找调用这个方法的实例对象,再到常量池中调用方法,如果找不到子类重写的这个方法,则实现父类的这个方法。

属性没有多态性,所以属性都用setter getter,open in terminal getField查看属性,只有静态解析。

强制转换:
父类作为形参,子类作为实参,调用方法时传入子类对象,表示的是自动的向上转型,可以调用子类覆写的父类的方法。
如果想调用子类独有的方法,可以向下强制转型。可以通过intenseOf判断,当传入不同的子类对象时实现不同的子类对象的独有的方法。子类不可以强制转换成另一个子类,否则会报错。ClassCastException.

抽象类
抽象类中的抽象方法使用abstract关键字,而且抽象方法没有方法体,子类继承父抽象类,必须实现其抽象方法,否则子类就要声明为抽象类。抽象类中可以定义私有的属性和构造器。调用子类的构造器创建实例对象时,也会调用父类的构造器。

接口
接口不需要再使用abstract关键字,里面的方法也不需要用。一个类可以实现多个接口。接口之间也可以互相继承。一个类只能继承一个父类。体现了JAVA类的单继承多实现的特点。

软件设计原则
开闭原则:对扩展开放,对修改关闭。增加功能而不修改原来的代码。
里氏代换原则:共有的方法写在父类中,由不同的子类去继承,并在此基础上增添新的方法,新的功能,而不去覆写父类的方法。
依赖倒转原则:接口抽象功能,面向接口编程。形参写接口或抽象类或父类。
单一原则:一个类只做一件事,一个类不要设计的太复杂。
接口隔离原则:对接口进行分类,并且接口应只包含客户感兴趣的方法。
迪米特法则:类和类之间保持相对独立性,减少互相调用。避免a事务挂了b事务像多米诺骨牌一样挂掉 。

模板方法设计模式:
接口定义抽象方法,封装流程,JAVA类实现方法,再创建一个新类调用方法。

策略方法设计模式:
1冒泡排序
2 在客户端暴露了方法的实现细节,comparable接口对user类的侵入性太强。user[i].comparable(user[i + 1])
3 抽象功能,实现功能,方法整合接口,客户端调用方法。

静态代码块在类加载到内存的时候会调用一次,实例代码块在创建对象时会调用一次,new创建几次对象就会调用几次实例代码块。在out编译的文件目录下,双击反编译,可以看到实例代码块放到构造器的第一行运行。

各种代码块的执行顺序:静态代码块,父类的静态代码块,子类的静态代码块,父类的构造器中的实例代码块,子类的构造器中的实例代码块。

静态属性在静态代码块中赋值putStatic。实例的属性在调用构造器时赋值putField。静态属性和静态方法储存在方法区且只有一份,其他方法也储存在方法区。实例的属性的值储存在堆中,创建多少个实例就会赋值多少次。静态属性和静态方法不需要创建实例,直接用类名和点函数就可以调用。

实例方法调用时可以省略this, static中没有this。项目开发时常用的常量可以用static final修饰,都是大写,统一避免出错。

内部类、私有化静态内部类、调用,是与外部类不同的两个类。

单例设计模式

//饿汉式
public class Singleton1 {

    //常量
    private static final Singleton1 INSTANCE = new Singleton1();

    //构造器
    private Singleton1(){

    }

    //方法
    public static Singleton1 getInstance(){
        return INSTANCE;
    }

}

//懒汉式
public class Singleton2 {

    //常量
    private static Singleton2 INSTANCE;

    //构造器
    private Singleton2(){

    }

    //方法 多线程时会出现问题
    public static Singleton2 getInstance(){
        if (INSTANCE == null){
            INSTANCE = new Singleton2();
        }
        return INSTANCE;
    }

}
//静态内部类实现单例
public class Singleton3 {

    //构造器
    private Singleton3(){

    }

    public static Singleton3 getInstance(){
        return Inner.INSTANCE; //第一次使用这个静态内部类,其加载到内存中
    }

    //静态内部类
    public static class Inner{
        public static final Singleton3 INSTANCE = new Singleton3();//?两个不同的类 private
        //类被加载到内存中以后,静态常量放到静态代码块里执行
    }


}

//多线程的单例模式
public class Singleton4 {

    //实例
    private volatile static Singleton4 INSTANCE;

    //私有化空参构造器
    private Singleton4(){};

    //公开的方法
    //双重检查锁
    public static Singleton4 getInstance(){
        if (INSTANCE == null){ //如果有实例对象就不让线程排队了直接返回
            synchronized (Singleton4.class){ //只允许一个线程创建
                if (INSTANCE == null){ //让之前没有实例时排队的线程不要再创建了锁被释放以后直接获取资源就可以了
                    INSTANCE = new Singleton4();//创建实例对象仍然有可能有对象半初始化的风险
                    return INSTANCE;
                }
            }
        }
        return INSTANCE;
    }


}

匿名内部类:
实现一个接口需要实现接口的方法。继承一个类不一定要重写那个类的方法。只使用一次的类可以使用匿名内部类。
剪头函数是匿名内部类删减只保留参数和代码。
函数式接口是有fuctionInterface注解且只有一个函数的接口。
学习函数式接口的目的是为了把函数作为参数传入到方法中。

值传递和引用传递:
引用传递传递的是对象的内存地址,可以修改掉传入的对象,也就是传入的实参、的属性的值。
值传递传递的是拷贝出来的数字,修改掉的是拷贝出来的基础数据类型的值,或者是string类型的值,string是final修饰的的不可变的字符串,被修改的是拷贝出来的、指向新的内存地址的值,和原来的值无关。

工具类utility
Arrays. to String():
先判断传过来的数组是不是空,是空就返回null,用传过来的数组长度减一,如果长度为零,减一为负一,说明没有值,就直接返回一个中括号,有值就直接StringBuilder和appen,for循环拼接字符串,等于最大下标时就return退出。

Arrays. equals():
数组地址相同。都不为空。长度相同。for循环比较内容。一致返回ture,否则返回false。

Arrays. sort():
排序

Arrays. binarySearch():
查找

Arrays. copyof():
传入要被拷贝的数组和新数组的长度,返回的是一个新数组。

Arrays. copyofRange():
拷贝哪个数组。从哪里开始拷贝到哪,包含前一个,不包含后一个,返回的是新数组。

System. arraycopy():
从原数组的,哪个下标开始拷贝,拷贝到新数组的哪个下标,拷贝原数组多长的数据,方法返回的是void,要用toString()打印新数组。

Date

StringBuilder效率更高,StringBuffer线程更安全。new对象,append就可以了。

异常类
循环中出现异常有两种解决办法:
判断条件,continue暂停此次循环,后面的代码不执行,继续下次循环。try catch捕获异常,尝试处理。

常见的error类:
OutOfMemoryError:内存溢出错误。把堆的初始内存和最大内存设置的非常小,放入很大的数据,把堆内存挤爆。
StackOverflowError:栈内存溢出错误。方法自己调用自己,没有合适的退出机制,把栈挤爆。
ClassNotFoundException:被调用的类编译时存在,运行时强行删除、让jvm找不到。

常见的exception类:
常见的检查性异常
IOException
SQLException
ClassNotFoundException:ClassForName()反射,根据类的全限定名称去加载一个类。
InterruptedException:当阻断方法收到中断请求时,就会抛出异常。

常见的非检查性异常
NotPointerException:空指针异常。在对象调用方法前,先判断对象是否是空,.equals()方法,前面是字符串常量,传入的是对象,避免空指针异常。
ArithmeticException:算术运算异常。
ClassCastException :类型转换异常。子类之间不能互相强转。
IndexOutOfBoundsException:下标越界异常。仔细检查,让数组的下标,在合理的范围内。
NumberFormatException:数字格式异常。判断是不是数字格式的字符串才转整型。

如果方法中有异常不处理,其他函数互相调用这个方法,就由最后调用这个方法的函数去接收异常,可以try catch避免运行中断跳出,但是在企业开发过程中try catch以后要处理,而不能生吞异常。自定义或设定不同的异常,而不用父类异常类,更好地去处理问题。
自定义异常类:自己打印的错误信息程序不会停止。

捕获异常,可以有针对性的先捕获具体的子类异常,最后放上父类的捕获意想不到的异常 undefinedException。
throws,用在方法名后面,一般是用在测试类。事务。
finally,是无论有没有捕获到异常都会强制执行的一段代码。

面试题:
try catch finally,如果只有try和catch中有return,没有捕获到异常则return try中的值,捕获到了则return catch中的值,如果try catch finally 都有return,那么可以从编译后的字节码文件中看到只有finally的return做了保留。

泛型
创建类时不确定传入的对象可以用表示,静态编译、new一个数组对象时可以使用泛型来限制传入的数据类型,不做限制调用方法或者打印的时候会报转型异常。使用泛型可以节省判断、强转的代码量。

泛型通配符
:不确定传入的泛型,等实现这个接口时再传入具体的类型。
?:无界。在方法调用中泛型与泛型没有继承关系。
?extends 类名:传入的是这个类的子类。
?super 类名:传入的是这个类的父类。

基础数据类型不能做泛型,Object和基础数据类型没有继承关系,但Integer可以使用,Integer是Object的子类。重载的方法中,只有泛型不同,是无法进行编译的,因为在编译的过程中有泛型擦除,所有泛型都会被编译成Object,只有泛型不同是无法实现方法重载的。

桥接方法:使用泛型在编译时,会编译成object而重写父类的方法必须函数名和参数列表相同,所以在实现接口重写方法时,其实是重载方法,而不是重写,参数列表已经改变,一个参数是传入的object,一个是传入的子类,所以,用桥接方法解决多态和泛型擦除的问题。

静态变量无法使用泛型,静态变量会放在静态代码块中执行,静态代码块会在类加载时执行一次,而泛型无法确定传入的类型,所以无法静态解析,更无法执行。
静态方法可以使用泛性,因为调用方法时会传入对象,确定了传入的对象就可以调用了。

枚举
一类字符串需要到处使用,有限且固定,就可以用枚举来实现。直接使用字符串不好修改,使用枚举的实例对象来代替字符串,在修改时只需要修改一个枚举类,整个项目的字符串都可以改变,不需要再一个一个的去修改字符串。

open in terminal javap -v .class
分析字节码:
双参构造器:L指引用数据类型,I指integer,V指没有返回值
new创建对象
ldc把字符串压到栈顶
iconst准备好常量
invokespecial调用构造器
putstatic赋值

name():父类的方法,枚举的对象的名字
ordinal():父类的方法,序号
values():编译器生成的方法,枚举类调用以后返回一个数组
valueof():也是编译器生成的方法,传入一个字符串返回一个枚举对象

枚举类也可以自己写属性和构造器,在方法中遍历枚举数组打印属性的值。

枚举类实现单例设计模式:
私有化构造器
创建一个枚举类,创建枚举类的实例对象,依赖注入外部类。实例对象在实例化时会调用构造器(字节码文件),构造器中创建外部类的实例对象。
公开的方法调用枚举类实例对象的属性

package review.Eumn;

//枚举类实现单例设计模式
public class Singleton {

    //构造器
    private Singleton(){}

    //公开的方法
    public static Singleton getInstance(){
        return Season.INSTANCE.singleton;
    }

    //枚举类
    public enum Season{
        INSTANCE;
        private Singleton singleton;
        private Season(){
            singleton = new Singleton();
        }
    }

}

枚举类的命名规范:每一个实例对象都应该写上注解,所有单词都要大写,单词和单词之间要用下划线隔开。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值