重拾java基础
虽然做了很久的开发,但是总是觉得自己基础不太牢固,对一些东西有些模糊,重新回顾一下以前可能没有注意到的知识点(不定期更新)
局部变量和成员变量得区别
1.定义位置上的区别
成员变量定义在方法体之外,类之内
局部变量定义在方法体之内
2.作用上的区别
成员变量描述一个对象的公共属性
局部变量只是在方法内使用
3.生命周期的区别
成员变量的生命周期跟随对象的生命周期
局部变量跟随方法的周期,方法执行时到创建成员变量的地方被创建,方法执行完毕时候马上从内存中消失
4.初始值的区别
成员变量都会有默认的初始值,如int 的初始值为0,boolean 的初始值为false float的初始值为0.0f
局部变量是没有默认的初始值的,在调用之前必须先进行初始化。否则编译器会报错。
匿名对象注意事项和应用场景
1我们一般不给匿名对象的某个属性赋予属性值,因为不可能调用得到。
2两个匿名对象在内存中指向不同的内存地址,不==
应用场景
如果对象需要调用一个方法,而且调用完这个方法之后,该对象就不再使用了,这时候使用匿名对象比较合适。
封装的作用
1.隐藏内部实现,外部只需调用即可
2.提高数据的安全性
构造代码块与构造函数
构造代码块对所有对象进行统一的初始化(先于构造函数执行)
构造函数对对应的对象进行初始化
this关键字
如果存在同名的成员变量与局部变量,在方法内部默认是访问局部变量的数据,可以通过this关键字访问到成员变量。
在构造函数中可以调用另一个构造函数初始化对象。
this关键字不能在构造函数中相互调用,因为这样是一个死循环。
如果在一个方法中访问到一个变量,并且该变量只存在于成员变量中,编译器会自动添加this关键字以访问成员变量。
static关键字
静态数据的生命周期:静态代码块是在class文件加载到内存中的时候执行, 不用等到创建对象,所以静态的数据优先于对象而存在。静态成员是随类的加载而创建,随类文件的消失而消失,。非静态成员随对象的创建而创建,随gc回收而消失。
static声明的成员变量存在于方法区的静态数据共享区,不在堆内存和栈内存,只在方法区维护一份,非静态的成员变量在每个对象中都会维护一份。
static修饰的方法,可以通过对象或者类名进行调用(一般直接使用类名访问),而非静态函数只能通过对象进行调用。静态方法不能访问非静态的变量,和方法(非静态的函数和变量以及this和super都是依赖于对象而存在,调用静态方法的时候对象不一定已经存在了。而对象存在的时候静态变量等早已在类加载的时候已经存在)。
静态函数不能出现this或super关键字
super关键字
当子类和父类存在同名的成员(包括属性和方法)时候,子类默认访问自己的成员。可以通过super调用父类的对应成员
创建子类对象时候会默认会先调用表父类的无参构造方法,可以通过super制定调用父类的某个构造方法。
重写与重载
1 方法重写时候方法名与形参列表必须一致
2 .重写时子类权限修饰符要大于或等于父类权限修饰符
3.子类返回值类型要小与或等于父类返回值类型
4.重写时候子类抛出的异常要小与或等于父类抛出的异常 |Exception最大
重载
1.函数名要一致
2.形参列表不一致(形参的个数或类型要不一致)
3.与返回值类型无关
instanceof关键字
作用:判断一个对象是否属于指定的类别(一般进行强制类型转换之前可以判断一下。如果false强制类型转换必然是会抛出异常的)
判断对象与指定类别需要存在继承或实现的关系
final关键字
1、修饰一个基本类型的变量时候,该变量不能被重新赋值,第一次的赋值则为最终的。
2、修饰一个引用类型的变量时候,该变量不能重新指向新的对象。(如果修饰数组或者其他容器类型时候纸指向的地址不能改变,但是数组的内部是可以发生改变 的)
3、修饰一个函数的时候,该函数不能被重写
4、修饰一个类的时候,该类不能被继承 如String
interface
1.接口算是一个特殊的类
2.接口的成员变量默认的修饰符 public static final
3.接口中的方法都是抽象方法,默认修饰符为 public abstract
4.接口没有构造方法
5.接口不能创建对象
6.非抽象类实现接口必须实现接口的所有方法。
作用
1、程序解耦
2、拓展功能
3、定义规范
多态
父类的引用类型指向子类对象或者是接口的引用类型指向实现了接口的类的对象
前提:继承 重写 向上转型
多态情况下子类父类存在相同成员时候,访问的是父类的,只有存在同名非静态的函数才是访问的子类的。且不能访问子类特有的成员。(实在要访问可以强制类型转换)
内部类
1.内部类可以访问外部类的所有成员
2.如果外部类与内部类存在同名的成员,默认访问的是内部类的。如果想要访问外部类的,可以用外部类.this.变量访问到。
3.内部类中如果出现了static成员。则他自己也要用static修饰
4.如果局部内部类(方法中的内部类)中访问到了一个局部变量。则这个局部变量需要用final修饰(防止方法执行完毕的时候变量被回收。而局部内部类的生命周期比局部变量长,它需要等到gc回收。)
线程
运行状态下的线程调用sleep或者wait方法,线程会进入临时阻塞状态,如果是调用的sleep,线程一旦超过sleep指定的时间将会进入可运行状态,如果是调用的wait方法,需要其他的线程唤醒该线程才可以重新进入可运行状态。
线程的生命周期状态图.png
线程中的成员变量需要声明为static共享给多个线程对象使用,否则在多个线程对象中各自有一份改成员变量。
出现线程安全的原因:存在两个或2个以上的线程对象,而且他们共享着一个资源。
有多个语句操作了共享资源。
解决方案:同步代码块(或者同步方法)
注意事项
1.任意一个对象都可以作为锁对象,锁对象必须是唯一的
2.在同步代码块中调用sleep方法是不会释放锁的
3.只有真正存在线程安全问题的时候才需要同步代码块,否则会降低效率。
wait与notify方法,注意事项
1.他们都是属于Object对象的。
2.他们必须在同步代码块或者同步函数中才能调用。
3.必须由他们的锁对象调用。
wait():一个线程如果调用了wait方法,那么该线程会进入一个以锁对象为标识符的线程池中等待。
notify():如果一个线程调用了notify方法,那么会唤醒以锁对象标识符的线程池中的等待线程中的一个。
集合
----collection
----List 特点:有序,可重复。
---------ArrayList 底层维护的是一个Object数组(内存地址连续),查询快,增删慢
---------LinkedList 底层是链表实现 ,增删快,查询慢
---------Vector 与ArrayList原理相同,但是是线程安全的,效率略低
----Set
---------HashSet 底层(哈希表)实现。特点 :存取快。
注意 :往里面添加元素的时候会调用hashCode获得哈希值,再经过运算得到它在哈希表中的位置。(如果得到的位置还没有元素,则直接存入,如果已经有元素了,会再调用equals方法)
---------TreeSet 底层使用红黑树数(二叉树)数据结构实现。如果元素具备自然顺序,则会按照自然顺序进行顺序存储。如果不具备排序能力,可以通过让要比较的类实现Comparable接口。在compareTo方法中实现排序规则。或者给TreeSet传入自己的比较器(自己创建一个类,实现Compartor接口)。
---------LinkedHashSet
----Map
----HashMap 底层基于哈希表实现。和hashset一样,调用见的hashcode得到元素哈希值。如果不存在该元素,则放入,如果已存在,则调用equals方法进行比较。如果返回false则进行存储,否则被视为重复元素。后出现的会覆盖前面的Map的值。
----TreeMap 底层基于二叉树。对键进行排序。
----HashTable 与HashMap特点差不多。不过是线程安全的。
泛型
函数上泛型的定义格式如
public <泛型声明> 返回值类型 函数名(泛型 变量名){}
public <T>T getData(T data){ return data;}
泛型类
修饰符 格式 class 类名<泛型>{
}
1.声明为泛型类的时候创建对象需要传入泛型的具体类型,如果不指定默认为Object
2.类声明的泛型只使用用非静态方法。静态函数需要独立声明。因为静态优先于对象存在,所以类中的静态方法需要单独进行泛型声明
泛型接口
interface 名称<泛型>{}
注意,使用接口时候应明确具体类型或者在该类也使用泛型声明。
待续。。。