java基础复习(数据类型、面向对象、static关键字、内部类、异常、注解、反射)

一、java中的数据类型

java中共分为四类八种基本数据类型:

  1. 整型
    byte: -128~127(-2的7次方到2的7次方-1)
    short:-32768~32767(-2的15次方到2的15次方-1)
    int:-2147483648~2147483647(-2的31次方到2的31次方-1)
    long:-9223372036854774808~9223372036854774807(-2的63次方到2的63次方-1)

  2. 浮点型
    float:3.402823e+38~1.401298e-45(e+38 表示乘以10的38次方,而e-45 表示乘以10的负45次方)
    double:1.797693e+308~4.9000000e-324(同上)

  3. 字符型:char

  4. 布尔型:boolean

在这里插入图片描述
下面是测试代码,重点看注释!

public class DataType {

    public static void main(String[] args) {

        // 整型(整数)
        byte a = 127;
        short b = 32767;
        int c = 2147483647;
        long d = 9223372036854774807L; //  long类型后面要加上L,不加就会将此数按照int来处理

        //浮点型(小数)
        float e = 3.14f; // 默认情况下,小数都是double类型的,若要声明为float类型,则后面要加f (和上面的long类似)
        double f = 4.4567;

        //字符型 (Java开发需尽量避免使用char类型,
        // 原因:char使用utf-16编码,改编码方式最多65536种且此编码已淘汰,java的Unicode编码后来新增了很多,
        // 所以导致新增的Unicode需要用两个char来表示一个Unicode,这样会导致程序可能出现未知的错误)
        char g = '国';
        // what's 编码?
        // 计算机底层是2进制的只认识1和0,所以我们制定了许多编码,
        // 比如最初的ASCII,大写字母A 对应65,小写a 97 等,用这些编码协议来使计算机认识并输出我们需要的文本

        //布尔型
        boolean flag = true;

        // 数据类型大小排列顺序:
        // double > float > long > int > short > byte


        int b1 = 128;
        long b3 = b1; // 小的数据类型转大的,自动转换

        // 大的转小的(或者char和其他6种数据类型转换),必须强制转换,
        // 但是要考虑内存溢出,比如b1是128,但是byte范围是-128-127,此时强转就会内存溢出,导致b2的值出错
        byte b2 = (byte) b1;

    }
}

二、面向对象

面向对象的三大特征:封装、继承、多态

封装:通常认为封装就是把数据和操作数据的方法绑定起来,对外部只提供一个定义好的接口。封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。

继承:继承是从已有类得到继承信息创建新类的过程。

public class B {

    public  void test(){
        System.out.println("B-->test()");
    }
}
public class A extends B{

    // 方法重写: 静态方法不存在重写,重写和静态方法无关,
    // 重写也是多态的一种

    @Override
    public void test(){
        System.out.println("A-->test()");
    }

}
public static void main(String[] args) {
        A a = new A();
        a.test();// A继承了B,重写了test方法,所以这里会输出:A-->test(),若A不重写,则调用的就是B的test方法,输出B-->test()

        B b = new A(); // 此处是向上转型(自动,A转为B ),向下转型需要强转
        b.test(); // 输出:A-->test()

       
}

多态:多态性是指允许不同子类型的对象对同一消息作出不同的响应。说的再简单一些就是,用同样的对象调同样的方法,但是却做了不同样的事情(其实就是一个声明的父类有不同的子类实现,或者一个接口有多个实现类,所以相同的父类对象或接口对象调同样的方法,因为实例化的子类或实现类不同,所以做出了不同响应)。多态指的是方法的多态。

要实现多态的必要条件:

  1. 方法重写
  2. 父类引用指向子类对象(Animal a = new Cat(),向上转型)

三、static关键字、抽象类、接口、内部类

static关键字:可以用来修饰成员变量和成员方法,被static修饰的成员变量或方法是属于类的,不单单属于某个对象,所以这些成员变量或方法是可以直接通过 类名. XXX 来访问的。
注意:被static修饰的成员变量是属于类的,之后创建的每个对象都共享这同一个类变量的值任何对象也都可以修改此变量值

/**
 * 此类为static关键字的详解
 */

public class StaticDemo {

    /**
     * 执行顺序:
     *  静态代码块执行--
        main方法执行--
        非静态代码块执行--
        构造方法执行--
     */

    // 被static修饰的变量和方法,可通过类名直接调用
    static final double PI =3.14;

    {
        System.out.println("非静态代码块执行--");
    }

    // 静态代码块:随着类的加载而执行,而且只执行一次
    static {
        System.out.println("静态代码块执行--");
    }

    public StaticDemo() {
        System.out.println("构造方法执行--");
    }

    public static void main(String[] args) {
        System.out.println("main方法执行");
        StaticDemo staticDemo = new StaticDemo();
    }


}

抽象类:抽象类中可以没有抽象方法,但是有抽象方法的类必须是抽象类。继承该抽象类的子类,必须重写抽象方法。抽象方法其实就是一种约束。

public abstract class AbstractDemo {

    // 抽象方法可以当做是一种约束吧!
    public abstract void test();
}
public class Z extends AbstractDemo{
    @Override
    public void test() {
        System.out.println("zzzzzz");
    }
}
public static void main(String[] args) {
    AbstractDemo abstractDemo = new Z();
    abstractDemo.test();
}

接口:java中的接口其实就是一堆抽象方法的集合,它和类不同,接口里主要是方法,接口无法实例化,但是可以被某个类实现它。简单来说接口其实就是一组定义好的规则,其他类去实现这些接口,重写里面的所有方法。一个类可以实现多个接口。

public interface UserService {
    public void addUser();
}
public interface PersonService {
}
// 一个类可以实现多个接口,这也就弥补了java无法多继承这一特点了
public class UserServiceImpl implements UserService,PersonService {
    @Override
    public void addUser() {
        System.out.println("增加一个用户--");
    }
}
public class ServiceTest {
    public static void main(String[] args) {

        //  接口引用指向实现类,这也是多态的提现了
        UserService userService = new UserServiceImpl();
        userService.addUser();
    }
}

内部类:内部类中又分为普通内部类、局部内部类、静态内部类、匿名内部类等,这些内部类认识即可,一般开发中不会用到,一些框架的源码中可能会用到。其中匿名内部类在lambda表达式中使其写法获得了精简,所以匿名内部类需要掌握。

// 以下的这些各种内部类了解即可,开发中一般来说用不到,但是要能看懂,有些框架的源码里可能会有
public class Outer {

    private int id = 9527;
    public void out(){
        System.out.println("这是外部类的方法");
    }

    // 内部类
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }

        public void getOuterID(){
            System.out.println("内部类,可以获取到外部类的私有属性:id="+id);
        }

    }

    public void in00(){
        // 局部内部类,在方法里创建
        class Inner00{
        }

    }

    // 静态内部类
    public static class Inner02{
        public void in(){
            System.out.println("静态内部类,无法获取外部类id,因为静态类是最先执行的");
        }
    }
}

// 这也是一个类,但注意同一个.java文件下只能有一个public修饰的类
class Inner03{
    public void in03(){
        System.out.println("Inner03");
    }
}

匿名内部类的实现:

public class OutTest {
    public static void main(String[] args) {
        Outer out = new Outer();
        // 内部类的创建方式
        Outer.Inner inner = out.new Inner();
        inner.getOuterID();

        Inner03 inner03 = new Inner03();
        inner03.in03();

        // 匿名内部类,也就是只有实例,没有对应的变量(也就是栈里没变量名,堆里有实例)
        new Outer().out();
        UserService userService = new UserService() {
            @Override
            public void add() {
                System.out.println("增加一个用户");
            }
        };
        userService.add();
    }
}

四、异常

java中的异常结构图如下:
在这里插入图片描述
可以看到,所有的异常根类为Throwable,下面分为Error和Exception,其中Error表示应用程序本身无法克服和恢复的一种严重问题;Exceotion表示程序还能够克服和恢复的问题,它下面又分为两种异常,运行时异常RuntimeException和非运行时异常(也叫编译时异常)CheckedException,其中CheckedException是必须要解决的,否则无法编译。

public class ExceptionTest {

    // throws 用在方法声明后面,throws表示可能会出现的异常,但是并不一定会发生这种异常
    public static void main(String[] args) throws Exception{

        int a =1 ;
        int b =0;

        // 快捷键:ctrl+alt+t
        try {
            if(b==0){
                // throw  主动抛出异常,用在方法体内
                throw new ArithmeticException();
            }
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally代码块执行");
        }

    }
}

自定义异常:java虽然本身提供了丰富的异常处理类,但有时候这些异常类还是满足不了开发中一些特定的需求,所以需要自定义异常。自定义异常的写法就是编写一个类继承Exception类,那这个类就属于一个自定义异常类了。

// 自定义异常类
public class MyException extends Exception{

    private int detail;

    public MyException() {
    }

    public MyException(int a) {
        this.detail = a;
    }

    // 自定义异常必须重写toString方法,toString方法也就是对该异常的描述
    @Override
    public String toString() {
        return "触发了自定义异常:MyException{" +
                "detail=" + detail +
                '}';
    }
}
// 测试自定义异常
public class Test {

    public static void main(String[] args) {

        try {
            test(6);
        } catch (MyException e) {
            e.printStackTrace();
            System.out.println(e); // 重写了toString方法,所以可以直接输出e
        }

    }

    static void test(int a) throws MyException{
        // 当a大于5时,抛出自定义异常
        if(a>5){
            throw new MyException(a);
        }

    }
}

常见的一些RuntimeException

  1. NullPointerException 空指针异常
  2. ClassNotFoundException 指定的类找不到
  3. ClassCastException 数据类型转换异常
  4. SQLException SQL 异常
  5. IndexOutOfBoundsException 数组角标越界异常
  6. NoSuchMethodException 方法不存在异常

五、注解

注解,顾名思义,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的。
Java注解又叫java标注,java提供了一套注解机制,使得我们可以对方法、类、参数、包、域以及变量等添加标准(即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用

简单来说,注解可以放到类、方法、参数等位置上,表示对这些域或变量添加一些标准一些信息。然后通过java中的反射机制可以将这些注释内容提取出来并使用。可以说注解是反射机制的一种实现方式。

元注解:@Target、@Retention、@Documented、@Inherited 就是负责注解其他注解

/**
 * 注解的作用:
 * 1.不是程序本身,可以对程序作出一些解释,和注释差不多
 * 2.可以被其他程序(如编译器等)读取
 *
 * 其实注解就是根据反射来得到注解的内容,从而对程序做出相应的响应,
 * 注解也就是反射的一种应用场景
 *
 *  以下4个是元注解,元注解的作用就是负责注解其他注解
 */

@Target(ElementType.METHOD)//表示注解可以用在哪些地方(方法上、类上等,可以写多个值)
@Retention(RetentionPolicy.RUNTIME)// 表示注解在哪些地方有效,runtime(运行时)>class(class文件)>sources(源码中)
@Documented // 表示是否将我们的注解生成在javadoc中
@Inherited // 子类可以继承父类的注解
public @interface YuanAnno {

}

class Test{

    @YuanAnno
    public void test(){

    }

}

自定义注解: 可以用@interface来声明一个自定义注解

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnno {

    // 注解中的参数怎么写? 参数类型+参数名();  和类中的参数定义相比多了一个()
    String name() default "";

    int age();

    int id();

    String[] arr() default {"勇士", "篮网"};//可以给参数一个默认值
}

class Test02 {

    // 如果注解中的参数没有默认值,这里就必须写参数,若有,可以不写
    @CustomAnno(id = 35, age = 23)
    public void test() {

    }

}

六、反射(重点)

反射是java中很重要的一个特性,java中的所有框架mybatis、spring、springmvc等全部运用了反射,反射是构建框架的基础也是精髓所在!反射在日常开发中不经常用到,是因为框架已经帮我们做好了,学好反射是理解框架底层原理的必要条件。

反射,顾名思义,‘’过来的,那与之相对的就是‘’,首先要先理解正是什么?
在java中我们创建一个对象一般都是:

Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);

这里创建对象的过程就是正,首先在编写这段代码前,因为我们知道我们需要一个Person类,所以我们主动去创建new一个Person类,并调用该类的方法。new 的这个动作就是我们主动创建的,这也就是正。

而反射,就是与正相对,我们在编写代码前并不知道要创建什么类,但问题是我还需要对即将创建的这个类做一些事情,这个时候就需要用到反射。

Class clz = Class.forName("com.hhl.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);

从以上两种正和反可以看出,普通的创建对象,是我们在编译期就知道需要哪个类,所以直接创建了相应的类,而反射是在编译期并不知道需要哪个类,是在程序运行时动态去加载创建类的

其实看到上面反射的代码有的人会有疑问,我获取Class对象时已经把需要的类的路径写好了,这不就说明在编译期我已经知道要创建Apple类了吗,为啥还通过反射,岂不是多此一举吗?

  1. 这里要说明的是,上面的反射代码是为了让我们理解而反射而写的,首先这个com.hhl.reflect.Apple里的这个Apple类可能在我们编写这段反射代码时还没写好(或者说这个Apple类是另一个程序员在写),但是我现在又必须用到这个Apple类,那怎么办?就可以用反射来创建对象并应用。
  2. 以Spring框架IOC为例,都说spring是一个容器,那么spring是如何帮我们管理并实例化bean的呢?可以在对象上面加注解@Compent或者在配置文件中写:
<bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean>  

spring帮我们实例化并管理bean是在我们程序启动时,运行时去实例化的,但程序运行时spring并不知道我们项目哪些类需要被它管理,所以我们要写配置文件或者注释告诉spring哪些类需要被它管理,然后spring通过这些配置文件中写的bean路径,再根据反射的特性就可以用反射来实例化对象并管理。 这也就是为什么说框架是半成品软件,因为是需要我们的配置+框架=项目。所以说反射是框架设计的精髓,没有反射,Spring框架就无法在程序运行时动态的去实例化对象并管理。

上面只是解释了反射在Spring框架中的一个提现,框架用到反射的地方还有很多很多,可以说没有反射就没有框架的诞生了。

总结:java本身是一门静态语言,但是通过java反射的机制,使得java变成了一门准动态语言。反射最重要的特点就是在程序运行时动态的创建对象和编译,并可以获取该类的所有属性和方法

Class类:
先要理解一个概念,一个类可以创建多个对象,但是一个类在java内存中只有一个class对象,这个class对象包含了这个类的一切信息。Class对象是java反射的起源,反射机制的实现就是首先获取某个类的Class对象通过该Class对象对应的API 可以获取该类下的所有内容(变量、方法等一切内容,包括私有变量和方法也都可以获取到)。

获取Class对象的3种方式:

  1. Class.forName(“类路径”)
  2. 类名.class
  3. 对象.getClass() 方法

下面是反射中常用到的Class对象的一些API:

public class Test {
    public static void main(String[] args) throws Exception {

        // 获取class对象的3种方式
        Class c1 = Class.forName("com.hhl.reflection.Student");

        Class c2 = Student.class;

        Student student = new Student();
        Class c3 = student.getClass();

        // 根据class对象,获取类的相关信息
        System.out.println(c3.getName()); //  包名+类名
        System.out.println(c3.getSimpleName());// 类名

        Field[] fields = c3.getFields(); // 获取public属性
        Field[] declaredFields = c3.getDeclaredFields(); // 获取到类的所有属性,包括私有的
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        Field name = c3.getDeclaredField("name");// 获取指定属性
        System.out.println(name);

        Method[] methods = c3.getMethods(); // 获取所有public方法
        Method[] declaredMethods = c3.getDeclaredMethods();// 获取所有方法,包括私有的
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        // 获取指定方法
        Method getAge = c3.getMethod("getAge", null); //无参数,就是null
        Method setAge = c3.getMethod("setAge", int.class);// 有参数,必须写参数class对象,因为要区分方法重载
        System.out.println(getAge);
        System.out.println(setAge);


        // 获得类的构造器,也就是构造方法
        Constructor[] constructors = c3.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        // 获取指定有参构造器
        Constructor constructor = c3.getConstructor(int.class, String.class, int.class);
        System.out.println(constructor);


    }
}

利用反射机制,创建实例对象、执行方法:

public class Test02 {
    public static void main(String[] args) throws Exception {

        Class c1 = Class.forName("com.hhl.reflection.Student");

        // 利用反射,class对象创建实例对象
        Student s2 = (Student) c1.newInstance();

        // 根据构造器创建对象
        Constructor constructor = c1.getConstructor(int.class, String.class, int.class);
        Student s3 = (Student) constructor.newInstance(35, "杜兰特", 7);


        Method study = c1.getMethod("study",null);
        // invoke,激活的意思, 执行方法,@param1 对象实例, @param2 方法参数
        study.invoke(s2,null);

        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);// 若字段或者方法是私有的,这里需要关闭安全检测,将Accessible设置为true
        name.set(s2,"詹姆斯");

        System.out.println(s2);


    }
}

通过反射,获取注解和注解中的属性值内容(这也是框架中经常用到的,比如获取注解信息,然后生成自动的增删改sql):

/**
 * 通过反射,获取注解信息
 */
public class Test03 {

    public static void main(String[] args) throws Exception {

        Class c1 = Class.forName("com.hhl.reflection.Person");

        // 获取类上的所有注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        // 获取注解的value值
        LeiAoon leiAoon = (LeiAoon) c1.getAnnotation(LeiAoon.class);
        String value = leiAoon.value();
        System.out.println(value);

        // 获取注解中某个单独的属性值
        Field age = c1.getDeclaredField("age");
        FiledAnno annotation = age.getAnnotation(FiledAnno.class);
        System.out.println(annotation.filed());
        System.out.println(annotation.type());

    }
}

@LeiAoon("lg_person")
class Person{

    @FiledAnno(filed = "age",type = 1)
    private int age;
    @FiledAnno(filed = "name",type = 2)
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Target(ElementType.TYPE)//作用在类上
@Retention(RetentionPolicy.RUNTIME)
@interface LeiAoon{
    String value();
}

@Target(ElementType.FIELD)// 作用在属性字段上
@Retention(RetentionPolicy.RUNTIME)
@interface FiledAnno{

    String filed();
    int type();

}

java反射的优缺点:
优点:很多了,最大的优点就是提现在它的动态性上,可以实现运行时动态的创建对象和编译,使代码更加灵活。
缺点:就是对性能上有影响,且反射里的各种API比较多且复杂。

最后说一点,反射在平时开发中用到的不多,但是对于我们理解学习框架底层原理很重要,因为所有的框架几乎都用到了反射。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值