Java基础(2019.4.10)

前言

       本博客为个人复习时总结用,无商业目的,其大多数内容皆为博主整理所得,并非原创。侵删。


接口与抽象类区别

  • 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
  • 类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
  • Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
  • 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。

面向对象

面向对象

  • 封装:就是把属性私有化,提供公共方法访问私有对象。

  • 继承:当多个类具有相同的特征(属性)和行为(方法)时,可以将相同的部分抽取出来放到一个类中作为父类,其它类继承这个父类。继承后子类自动拥有了父类的属性和方法。
    但特别注意的是,父类的私有属性(private)和构造方法不能被继承。另外子类可以写自己特有的属性和方法,目的是实现功能的扩展,子类也可以复写父类的方法,即方法的重写。子类不能继承父类中访问权限private的成员变量和方法

  • 多态:简单来说就是“一种定义,多种实现”。同一类事物表现出多种形态。Java语言中有方法重载和对象多态两种形式的多态

  • 方法重载:在一个类中,允许多个方法使用同一个名字,但是方法的参数不同,完成的功能也不同

  • 对象多态:子类对象可以与父类对象进行相互转换,而且根据其使用的子类的不同,完成的功能也不同

  • 抽象:抽象是从许多事物中,舍弃个表的,非本质的属性,抽取出共同的,本质的属性的过程。抽象的过程就是比较的过程,通过比较找出事物之间的共同属性,通过比较区分本质。

       static关键字的中文含义是静态的意思。使用static修饰的成员变量,常量,方法和代码分别称为静态变量,静态常量,静态方法,静态代码块,它们统称为静态成员。静态成员归整个类所有,不依赖特定的实例,被类的所有实例所共享的。只要被JVM加载就可以根据类名在全局数据区内找到。

类的成员变量分为两种:
  • 实例变量 (ps:也就是没有被static关键字修饰的变量)
  • 静态变量
    成员变量
代码块

       代码块分为普通代码块,构造块,静态代码块

  • 静态代码块主要用于初始化类,为类的静态属性初始化,有以下几个特点:
  • 静态代码块不能存在于任何方法体内
  • 不能直接访问实例变量和实例方法(上面说过了原因)
  • JVM在加载类时就会执行静态代码块,所以静态代码块优先于主方法执行。
  • static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

       与C/C++中的static不同,Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。
       构造器:在new时调用,此时找到父类,再调用。此时类中全部都要信息调用。


内部类可以分为很多种,但是主要有4种内部类:静态内部类、成员内部类、局部内部类、匿名内部类。

  1. 静态内部类是指被声明为static的内部类,不能访问外部类的普通成员变量,只能访问外部类中的静态成员变量和静态方法。
  2. 去掉关键字static就是成员内部类,可以自由的引用外部类的属性和方法。
  3. 局部内部类是指定义在一个代码块内的类,作用范围为其所在的代码块。局部类类似于局部变量一样,不能被public、protected、private以及static修饰,只能访问方法中定义为final类型的局部变量。
  4. 匿名内部类,是一种没有类名的内部类,不使用关键字class、extends、implements,它必须继承其他类或实现其它接口。
  • 匿名内部类不能有构造函数
  • 不能定义静态成员、方法和类
  • 不能是public、protected、private、static。
  • 只能创建匿名内部类的一个实例

object类方法

  1. clone方法
    保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
  2. getClass方法
    final方法,获得运行时类型。
  3. toString方法
    该方法用得比较多,一般子类都有覆盖。
  4. finalize方法
    该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
  5. equals方法
    该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
  6. hashCode方法
    该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
    一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
  7. wait方法
    wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
    调用该方法后当前线程进入睡眠状态,直到以下事件发生。
  • 其他线程调用了该对象的notify方法。
  • 其他线程调用了该对象的notifyAll方法。
  • 其他线程调用了interrupt中断该线程。
  • 时间间隔到了。
    此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
  1. notify方法
    该方法唤醒在该对象上等待的某个线程。
  2. notifyAll方法
    该方法唤醒在该对象上等待的所有线程。

反射

https://www.cnblogs.com/whgk/p/6122036.html

       在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
       想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
       获取字节码文件对象的三种方式。

  1. Class clazz1 = Class.forName(“全限定类名”);  //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。加载
  2. Class clazz2 = Person.class;    //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。初始化
  3. Class clazz3 = p.getClass();    //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段 应该是使用阶段

动态代理与静态代理

静态代理:

实现类

public class UserManagerImpl implements UserManager {  
  
    @Override  
    public void addUser(String userId, String userName) {  
        System.out.println("UserManagerImpl.addUser");  
    }  
  
}  

代理类

public class UserManagerImplProxy implements UserManager {  
  
    // 目标对象  
    private UserManager userManager;  
    // 通过构造方法传入目标对象  
    public UserManagerImplProxy(UserManager userManager){  
        this.userManager=userManager;  
    }  
    @Override  
    public void addUser(String userId, String userName) {  
        try{  
                //添加打印日志的功能  
                //开始添加用户  
                System.out.println("start-->addUser()");  
                userManager.addUser(userId, userName);  
                //添加用户成功  
                System.out.println("success-->addUser()");  
            }catch(Exception e){  
                //添加用户失败  
                System.out.println("error-->addUser()");  
            }  
    }    
}  

客户端调用:

public class Client {  
  
    public static void main(String[] args){  
        //UserManager userManager=new UserManagerImpl();  
        UserManager userManager=new UserManagerImplProxy(new UserManagerImpl());  
        userManager.addUser("1111", "张三");  
    }  
}  
动态代理:
  1. new出代理对象,通过实现InvacationHandler接口,然后new出代理对象来。

  2. 通过Proxy类中的静态方法newProxyInstance,来将代理对象假装成那个被代理的对象,也就是如果叫人帮我们代买火车票一样,那个代理就假装成我们自己本人

  3. 执行方法,代理成功

     /**   
      *    
      * JDK动态代理类   
      *    
      *   
      */    
     public class JDKProxy implements InvocationHandler {    
     
    	 private Object targetObject;//需要代理的目标对象    
     
         public Object newProxy(Object targetObject) {//将目标对象传入进行代理    
             this.targetObject = targetObject;     
             return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),    
                     targetObject.getClass().getInterfaces(), this);//返回代理对象    
         }    
         
         public Object invoke(Object proxy, Method method, Object[] args)//invoke方法    
                 throws Throwable {    
             before();
             Object ret = null;      // 设置方法的返回值    
             ret  = method.invoke(targetObject, args);       //invoke调用需要代理的方法
             after();
             return ret;    
         }    
     
         private void before() {//方法执行前   
             System.out.println("方法执行前 !");    
         }    
         private void after() {//方法执行后    
             System.out.println("方法执行后");    
         }    
     }  
    

       区别:

  • 静态代理每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
    所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理
    底层用到的技术是反射。

Java引用

       强引用,软引用,弱引用,虚引用

强:

       通常使用的方式。
       如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

软:

       被软引用关联的对象只有在内存不足时才会被回收
       如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;
       如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
       SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。

MyObject aRef = new  MyObject();  
SoftReference aSoftRef=new SoftReference(aRef); 
弱:

       弱引用关联的对象在JVM进行垃圾回收时总会被回收。
       弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。

WeakReference<People>reference=new WeakReference<People>(new People("zhouqian",20));  
虚:

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

       要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

       引用队列:

ReferenceQueue<String> queue = new ReferenceQueue<String>();  

static加载顺序问题:

  1. 下面这段代码的输出结果是什么?

     public class Test extends Base{
      
         static{
             System.out.println("test static");
         }
          
         public Test(){
             System.out.println("test constructor");
         }
          
         public static void main(String[] args) {
             new Test();
         }
     }
    
     class Base{
          
         static{
             System.out.println("base static");
         }
          
         public Base(){
             System.out.println("base constructor");
         }
     }
     输出:
     base static
     test static
     base constructor
     test constructor
    

       至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。

  1. 这段代码的输出结果是什么?

     public class Test {
         Person person = new Person("Test");
         static{
             System.out.println("test static");
         }
          
         public Test() {
             System.out.println("test constructor");
         }
          
         public static void main(String[] args) {
             new MyClass();
         }
     }
      
     class Person{
         static{
             System.out.println("person static");
         }
         public Person(String str) {
             System.out.println("person "+str);
         }
     }
      
      
     class MyClass extends Test {
         Person person = new Person("MyClass");
         static{
             System.out.println("myclass static");
         }
          
         public MyClass() {
             System.out.println("myclass constructor");
         }
     }
     输出:
     test static
     myclass static
     person static
     person Test
     test constructor
     person MyClass
     myclass constructor
    

       类似地,我们还是来想一下这段代码的具体执行过程。首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。


finally块和return

首先一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

	public static void main(String[] args)
{
    int re = bar();
    System.out.println(re);
}
private static int bar() 
{
    try{
        return 5;
    } finally{
        System.out.println("finally");
    }
}
/*输出:
finally
*/

finally中的return 会覆盖 try 或者catch中的返回值。

	public static void main(String[] args)
    {
        int result;

        result  =  foo();
        System.out.println(result);     /2
 
        result = bar();
        System.out.println(result);    /2
    }
 
@SuppressWarnings("finally")
public static int foo()
{
    trz{
        int a = 5 / 0;
    } catch (Exception e){
        return 1;
    } finally{
        return 2;
    }

}

@SuppressWarnings("finally")
public static int bar()
{
    try {
        return 1;
    }finally {
        return 2;
    }
}

finally中的return会抑制(消灭)前面try或者catch块中的异常

class TestException
{
    public static void main(String[] args)
    {
        int result;
        try{
            result = foo();
            System.out.println(result);           //输出100
        } catch (Exception e){
            System.out.println(e.getMessage());    //没有捕获到异常
        }
 
        try{
            result  = bar();
            System.out.println(result);           //输出100
        } catch (Exception e){
            System.out.println(e.getMessage());    //没有捕获到异常
        }
    }
 
//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception
{
    try {
        int a = 5/0;
        return 1;
    }catch(ArithmeticException amExp) {
        throw new Exception("我将被忽略,因为下面的finally中使用了return");
    }finally {
        return 100;
    }
}

//try中的异常被抑制
@SuppressWarnings("finally")
public static int bar() throws Exception
{
    try {
        int a = 5/0;
        return 1;
    }finally {
        return 100;
    }
 }
}

finally中的异常会覆盖(消灭)前面try或者catch中的异常

	class TestException
{
    public static void main(String[] args)
    {
        int result;
        try{
            result = foo();
        } catch (Exception e){
            System.out.println(e.getMessage());    //输出:我是finaly中的Exception
        }

    try{
        result  = bar();
    } catch (Exception e){
        System.out.println(e.getMessage());    //输出:我是finaly中的Exception
    }
}

//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception
{
    try {
        int a = 5/0;
        return 1;
    }catch(ArithmeticException amExp) {
        throw new Exception("我将被忽略,因为下面的finally中抛出了新的异常");
    }finally {
        throw new Exception("我是finaly中的Exception");
    }
}

//try中的异常被抑制
@SuppressWarnings("finally")
public static int bar() throws Exception
{
    try {
        int a = 5/0;
        return 1;
    }finally {
        throw new Exception("我是finaly中的Exception");
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值