JAVA基础

基础部分
一.String、stringbuffer与stringbuilder

1、String 字符串常量
Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。

2、StringBuffer 字符串变量(线程安全)
类似于 String 的字符串缓冲区,预估初始化大小,较少扩容的次数。默认16个字节数组的大小,超过默认的数组长度时,则扩容为原来字节数组的长度*2+2。
1.增 
StringBuffer append(data);尾部添加 
StringBuffer insert(index,data);指定未知插入
2.删 
StringBuffer delete(int start, int end) 
StringBuffer deleteCharAt(int index):删除指定位置的元素
3.改 
StringBuffer replace(start,end,string); 
void setCharAt(index,char);
4.查 
char charAt(index); 
int indexOf(string);
5.清空
setLength(0)
new StringBuffer()
delete(0, sb.length())

3、StringBuilder 字符串变量(非线程安全)

二、引用方式
1.强引用
 是指创建一个对象并把这个对象赋给一个引用变量。
Object object =new Object();
String str ="hello";
 强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null。
2.软引用(SoftReference)
一个对象具有软引用,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。 一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。
3.弱引用
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。
4.虚引用(PhantomReference)

  虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

三、对象的生命周期
对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与释放阶段(Free)。上面的这7个阶段,构成了 JVM中对象的完整的生命周期。
1.在对象创建阶段,系统要通过下面的步骤,完成对象的创建过程:
(1)为对象分配存储空间。
(2)开始构造对象。
(3)递归调用其超类的构造方法。
(4)进行对象实例初始化与变量初始化。
(5)执行构造方法体。
  在创建对象时,应该遵循的规则
(1)避免在循环体中创建对象,即使该对象占用内存空间不大。
(2)尽量及时使对象符合垃圾回收标准。
(3)不要采用过深的继承层次。
(4)访问本地变量优于访问类中的变量。

2.应用阶段
对象整个生命周期中证明自身“存在价值”的时期。系统至少维护着对象的一个强引用(Strong Reference);

3.不可视阶段
在其他区域的代码中已经不可以再引用它,其强引用已经消失

4.不可到达阶段
处于不可到达阶段的对象,在虚拟机所管理的对象引用根集合中再也找不到直接或间接的强引用,这些对象通常是指所有线程栈中的临时变量,所有已装载的类的静态变量或者对本地代码接口(JNI)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。

5.可收集阶段、终结阶段与释放阶段
对象生命周期的最后一个阶段是可收集阶段、终结阶段与释放阶段。当对象处于这个阶段的时候,可能处于下面三种情况:
(1)垃圾回收器发现该对象已经不可到达。
(2)finalize方法已经被执行。
(3)对象空间已被重用。

当对象处于上面的三种情况时,该对象就处于可收集阶段、终结阶段与释放阶段了。虚拟机就可以直接将该对象回收了。


四、抽象类和接口
一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。抽象类是对根源的抽象,接口是对动作的抽象。抽象类可以类比为模板,而接口可以类比为协议。在抽象类中可以写非抽象的方法,从而避免在子类中重复书写他们,这样可以提高代码的复用性,这是抽象类的优势;接口中只能有抽象的方法。接口更有利于软件系统的维护和重构。
第一点. 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
第二点. 接口可以多继承,抽象类不行
第三点. 接口定义方法,不能实现,而抽象类可以实现部分方法。
第四点. 接口中基本数据类型为static 而抽类象不是的。

参数抽象类接口
默认的方法实现它可以有默认的方法实现接口完全是抽象的。它根本不存在方法的实现
实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器抽象类可以有构造器接口不能有构造器
与正常Java类的区别除了你不能实例化抽象类之外,它和普通Java类没有任何区别接口是完全不同的类型
访问修饰符抽象方法可以有publicprotecteddefault这些修饰符接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法抽象方法可以有main方法并且我们可以运行它接口没有main方法,因此我们不能运行它。
多继承抽象方法可以继承一个类和实现多个接口接口只可以继承一个或多个其它接口
速度它比接口速度要快接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。
五、内部类
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类: OuterClass.InnerClass innerClass = outerClass.new InnerClass();生成对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了。

场景:当某个类除了它的外部类,不再被其他的类使用时:1、不可能为其他的类使用;2、出于某种原因,不能被其他类引用,可能会引起错误。

为什么要设计内部类?
1 通过内部类 可以 实现多继承
2 通过内部类可以 把一个类的访问权限 降到最低,正常来说,创建一个类,最起码的访问权限就是包内其他类都可以访问,但是内部类可以设置为private ,只允许外部类使用,这样就升级了安全性。
3 通过内部类可以减少包内类的个数,增加了可读性,使得代码更加灵活和富有扩展性

1.成员内部类
       成员内部类是外围类的一个成员(方法),所以他是可以无限制的访问外围类的所有 成员属性和方法,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
       推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 。
2.局部内部类
       嵌套在方法内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
复制代码
public class Parcel5 {
    public Destionation destionation(String str){
        class PDestionation implements Destionation{
            private String label;
            private PDestionation(String whereTo){
                label = whereTo;
            }
            public String readLabel(){
                return label;
            }
        }
        return new PDestionation(str);
    }
    
    public static void main(String[] args) {
        Parcel5 parcel5 = new Parcel5();
        Destionation d = parcel5.destionation("chenssy");
    }
}
3.匿名内部类
    1、 匿名内部类是没有访问修饰符的。
    2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
    3、 当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
    4、 匿名内部类是没有构造方法的。
4.静态内部类
       非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
      1、 它的创建是不需要依赖于外围类的。
      2、 它不能使用任何外围类的非static成员变量和方法。

在静态内部类中可以存在静态成员。静态内部类只能访问外围类的静态成员变量和方法,不能访问外围类的非静态成员变量和方法

六、String类为什么要设计成不可变的

1.线程安全。字符串存储在常量池,常量池中的数据可以被共享,如果字符串可以修改将会导致,可能很多地方都在操作这个对象,尤其在多线程中是很危险的。
2.支持字符串常量池数据共享,节省资源,提高效率(因为如果已经存在这个常量便不会再创建,直接拿来用)。
七、Object类的equals()和hashCode()
对于Object类
1.equals()方法
针对包装对象,比较的是对象的值(包括 boolean,byte,char,short,int,long,float,double)
针对String对象,比较的也是String的值(因为String内部重写了equals方法和hashCode方法)
针对其他object对象,比较的是两个对象的引用是否指向同一个内存地址
2.hashCode()返回该对象的哈希码值
哈希算法是将数据依特定算法直接指定到一个地址上。可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。如果两个对象的hashCode相同,它们并不一定相同 ;在对象存储的散列表里面,hashCode用来指定对象存储的内存地址。而equals用来判断对象的引用是否指向同一个地址,也就是判断两个对象的hashCode值是否一致 

每个覆盖了equals() 方法的类中,也必须覆盖hashCode() 方法。如果不这样的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable。

一般有约定
hashCode相同时,equals方法一定返回true。

equals方法返回true时,hashCode一定相同。 

八、 AtomicInteger类   

普通的整型类如int和Integer类,在++i/i++等操作并不是线程安全的,在并发环境下容易出现脏数据。
AtomicInteger类是一个提供原子操作的Integer类。AtomicInteger使用了volatile关键字进行修饰,使得该类可以满足线程安全。

volatile的作用是使得多个线程可以共享变量,但是问题在于使用volatile将使得VM优化失去作用,导致效率较低,所以要在必要的时候使用,因此AtomicInteger类不要随意使用,要在使用场景下使用。

九、内存区域


方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。

常量池:常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。

堆区:内存中最大的一块,用于存放类的对象实例。

虚拟机栈:是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。

本地方法栈(Native Method Statck):本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,本地方法栈也是线程私有的。

十.逻辑地址与物理地址

进程使用虚拟内存中的地址,由操作系统协助相关硬件,把他“转换”成真正的物理地址。有了这样的抽像,一个程序,就能使用比真实物理地址大得多的地址空间。

物理地址,CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存、BIOS等)。在没有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同地址的物理存储器被读写;而在使用了虚拟存储器的情况下,虚拟地址不是被直接送到内存地址总线上,而是送到存储器管理单元MMU,把虚拟地址映射为物理地址。

        逻辑地址是在有地址变换功能的计算机中,访内指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址,也就是是机器语言指令中,用来指定一个操作数或是一条指令的地址。要经过寻址方式的计算或变换才得到内存储器中的实际有效地址即物理地址。

十一、减少重复的代码

1.定义一个基Activity或Fragment

2.代码的去重复技巧
从代码上去除重复的代码就是用通用的重构技巧,比如提炼方法,抽象基类,提炼常量等。

3.多用引用而不是写死
所有的资源的指定都可以用引用,而非直接写死,直接写死就会出现重复代码,比如颜色,背影,字串,布局,ID,度量(dimen),风格等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值