🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
java在安卓的开发中是非常重要的,所以今天我总结了一下java的基础知识,当然,还有一些没有总结完,例如网络编程,io流等,将会在下一篇博文中写出。 ## 概述 javac :负责的是编译的部分 java :负责运行的部分.会启动 jvm.加载运行时所需的类库,并对 class 文件进行执行 ## 语法规则 ### 数据类型 1 1 ): 基本数据类型:byte(1个字节)、short(2)、int(4)、long(8)、float(4)、double(8)、char(2)、boolean。 1个字节占8位 2 2 ): 引用数据 类型: 数组、类、接口。 ### 运算符 > *+ - * / % %:任何整数模 2 不是 0 就是 1,所以只要改变被模数就可以实现开关运算 > &: 只有两边都为 true 结果是 true。否则就是 false。 > |:只要两边都为 false 结果是 false,否则就是 true > & 和 && 区别: & :无论左边结果是什么,右边都参与运算。 &&: 短路与,如果左边为 false,那么右边不参数与运算。 > | 和 || 区别:|:两边都运算。 || : 短路或,如果左边为 true,那么右边不参与运算。 > ++X(–X)表示在使用x之前,先使x的值增(减)1 ### 语句 If switch do while while for 当判断固定个数的值的时候,建议使用 switch,效率相对较高。 当判断数据范围,获取判断运算结果 boolean 类型时,需要使用 if。 当某些语句需要执行很多次时,就用循环结构,建议使用 for。因为 for 循环完毕,变量在内存中释放。 ### 函数 重载的定义是:在一个类中,如果出现了两个或者两个以上的同名函数,只要它们的参数的个数,或者参数的 类型不同,即可称之为该函数重载了。 如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。 ### 数据 ~~~ // 二分查找法。必须有前提: 数组中的元素要有序。 public static int halfSeach_2(int[] arr,int key){ int min,max,mid; min = 0; max = arr.length-1; mid = (max+min)>>1; //(max+min)/2; while(arr[mid]!=key){ if(key>arr[mid]){ min = mid + 1; } else if(key<arr[mid]) max = mid - 1; if(max<min) return -1; mid = (max+min)>>1; } return mid; } ~~~ java 分了 5 5 片内存。 1 :寄存器。2 :本地方法区。3 :方法区。4 :栈。5 :堆。 ~~~ 栈:存储的都是局部变量 ( 函数中定义的变量,函数上的参数,语句中的变量 ); 只要数据运算完成所在的区域结束,该数据就会被释放。后进先出。 堆:用于存储数组和对象,也就是 实体。啥是实体啊?就是用于封装多个数据的。 1 :每一个实体都有内存首地址值。 2 :堆内存中的变量都有默认初始化值。因为数据类型不同,值也不一样。 3 :垃圾回收机制。 ~~~ ## 面向对象 ### 类 属性是用于存储数据的 , 直接被访问,容易出现安全隐患 , 所以,类中的属性通 常被私有化,并对外提供公共的访问方法。 这个方法一般有两个,规范写法:对于属性 xxx ,可以使用 setXXX(),getXXX() 对其进行操作 主函数的存在,仅为该类是否需要独立运行 , 如果不需要,主函数是不用定义的。 主函数的解释:保证所在类的独立运行,是程序的入口,被 jvm 调用。 构造函数是在对象创建时,就被调用,用于初始化, 而且初始化动作只执行一次。 一般函数,是对象创建后,需要调用才执行,可以被调用多次。 ### 封装 将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。 ### this 用 this 调用构造函数,必须定义在构造函数的第一行。因为构造函数是用于初始化的,所以初 始化动作一定要执行。 否则编译失败。 ### static ~~~ 关键字,是一个修饰符 , 用于修饰成员( ( 成员变量和成员函数) ) 静态方法只能访问静态成员,不可以访问非静态成员。 静态方法中不能使用 this ,super 关键字。 成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。 静态代码块、构造代码块、构造函数同时存在时的执行顺序: 静态代码块 à 构造代码块 à 构造函数 ~~~ ### 单例设计模式 保证一个类在内存中的对象唯一性。 步骤: 1 1 ,因为创建对象都需要构造函数初始化 ,只要将本类中的构造函数私有化,其他程序就无法 再 创建 该类对象; 2 2 ,就在类中创建一个本类的对象 ; 3 3 ,定义一个方法,。 返回该对象,让其他程序可以通过方法就得到本类对象。 (作用:可控) 代码体现: 1 1 ,私有化构造函数 ; 2 2 ,创建私有并静态的本类对象 ; 3 3 ,定义公有并静态的方法,返回该对象 ~~~ //饿汉式 class Single{ private Single(){} // 私有化构造函数。 private static Single s = new Single(); // 创建私有并静态的本类对象。 public static Single getInstance(){ // 定义公有并静态的方法,返回该对象。 return s; } } //懒汉式:延迟加载方式。 class Single2{ private Single2(){} private static Single2 s = null; public static Single2 getInstance(){ if(s==null) s = new Single2(); return s; } } ~~~ ### 继承 java 中对于继承,java 只支持单继承。java 虽然不直接支持多继承,但是保留了这种多继承机制,进行改良。 java 支持多重继承。A 继承 B B 继承 C C 继承 D。 子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。 super()和 和 this() 不可以同时出现的构造函数中。 在方法覆盖时,注意两点: 1:子类覆盖父类时,必须要保证,子类方法的权限必须大于等于父类方法权限可以实现继承。否则,编译 失败。 2:覆盖时,要么都静态,要么都不静态。 (静态只能覆盖静态,或者被静态覆盖) ### final 可以修饰类,方法,变量。不可以被继承、覆盖。 ### 抽象类 抽象类的特点: 1 1 : 抽象方法只能定义在 抽象类中 , 抽象类和抽象方法必须由 t abstract 关键字修饰 (可以描述类和 ) 方法,不可以描述变量) 。 2 2 : 抽象方法只定义方法声明,并不定义方法实现。 3 3 : 抽象类不可以被创建对象( ( 实例化) ) 。 4 4 : 只有通过子类继承抽象类并覆盖了抽象类中的 所有 抽象方法后,该子类 才 可以实例化。否则, 该子类还是一个抽象类。 抽象类可以大一非抽象方法,抽象类中有构造函数。 ### 接口 接口中有抽象方法,接口不可以实例化。 接口的子类必须实现了接口 中 所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。 类与类之间存在着继承关系,类与接口中间存在的是 实现关系。 继承用 extends ; 实现用 implements ### 多态 体现: 父类引用或者接口的引用指向了自己的子类对象。 //Animal a = new Cat(); instanceof ;// 判断对象是否实现了指定的接口或继承了指定的类 ### Object ~~~ public boolean equals(Object obj){ if(!(obj instanceof Person)) return false; Person p = (Person)obj; return this.age == p.age; } ~~~ 通常 equals , toString , hashCode ,在应用中都会被复写 , 建立具体对象的特有的内容。 ### 内部类 如果 A 类需要直接访问 B 类中的成员,而 B 类又需要建立 A 类的对象。这时,为了方便设计和访问, 直接将 A 类定义在 B 类中。就可以了。A 类就称为 内部类。内部类可以直接访问外部类中的成员。而外部类想要 访问内部类,必须要建立内部类的对象。 ~~~ class Outer{ int num = 4; class Inner { void show(){ System.out.println("inner show run "+num); } } public void method(){ Inner in = new Inner();//创建内部类的对象。 in.show();//调用内部类的方法。 } } ~~~ 匿名内部类: 当函数的参数是接口类型引用时,如果接口中的方法不超过 3 个。可以通过匿名内部类来完成参数的传递。 ### 异常 > 通过 throws 关键字完成, 格式: throws 异常类名, , 异常类名 > throw 用于抛出异常对象,后面跟的是异常对象;throw 用在函数内。 throws 用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws 用在函数上。 > 运行时异常,其中 Exception 有一个特殊的子类 RuntimeException,以及 RuntimeException 的子类是运 行异常,也就说这个异常是编译时不被检查的异常。 > finally 很有用,只要用户关闭资源。无论是否发生异常,资源都必须进行关闭。 System.exit(0); //退出 jvm,只有这种情况 finally 不执行。 常见 异常 : 1、脚标越界异常(IndexOutOfBoundsException)包括数组、字符串; 空指针异常(NullPointerException) 2、类型转换异常:ClassCastException 3、不支持操作异常; ### 包 常见的软件包: > java.lang : language java 的核心包,Object System String Throwable jdk1.2 版本后,该 包中的类自动被导入。 > java.awt : 定义的都是用于 java 图形界面开发的对象。 > javax.swing: : 提供所有的 windows 桌面应用程序包括的控件, 比如: Frame , Dialog, Table, List 等等, , 就是 java 的图形界面库 。 > java.net : 用于 java 网络编程方面的对象都在该包中。 > java.io : input output 用于操作设备上数据的对象都在该包中。比如:读取硬盘数据,往硬盘写 入数据。 > java.util a : java 的工具包,时间对象 , 集合框架。 > java.applet : application+let 端 客户端 a java 小程序。 server+let – > servlet 端 服务端 java 小程序 ### 多线程 创建线程: 方法1: ~~~ 步骤: 1,定义类继承 Thread 类; 2,目的是复写 run 方法,将要让线程运行的代码都存储到 run 方法中; 3,通过创建 Thread 类的子类对象,创建线程对象; 4,调用线程的 start 方法,开启线程,并执行 run 方法。 ~~~ 方法2: ~~~ 步骤: 1,定义类实现 Runnable 接口。 2,覆盖接口中的 run 方法(用于封装线程要运行的代码)。 3,通过 Thread 类创建线程对象; 4,将实现了 Runnable 接口的子类对象作为实际参数传递给 Thread 类中的构造函数。 为什么要传递呢?因为要让线程对象明确要运行的 run 方法所属的对象。 5,调用 Thread 对象的 start 方法。开启线程,并运行 Runnable 接口子类中的 run 方法。 Ticket t = new Ticket(); /* 直接创建 Ticket 对象,并不是创建线程对象。 因为创建对象只能通过 new Thread 类,或者 new Thread 类的子类才可以。 所以最终想要创建线程。既然没有了 Thread 类的子类,就只能用 Thread 类。 `*/` Thread t1 = new Thread(t); //创建线程。 /* 只要将 t 作为 Thread 类的构造函数的实际参数传入即可完成线程对象和 t 之间的关联 为什么要将 t 传给 Thread 类的构造函数呢?其实就是为了明确线程要运行的代码 run 方法。 `*/` t1.start(); ~~~ ### 同步 同步函数:其实就是将同步关键字定义在函数上,让函数具备了同步性。 同步函数使用的锁是 this , 静态同步函数的锁是 该类的字节码文件对象。 同步是隐示的锁操作,而 k Lock 对象是显示的锁操作,它的出现就替代了同步。 ## API ### 字符串 ~~~ parseInt(string,radix); //将给定的数转成指定的基数进制; 在 在 5 jdk1.5 版本后,对基本数据类型对象包装类进行升级。在升级中,使用基本数据类型对象包装类可 以像使用基本数据类型一样,进行运算。 Integer i = new Integer(4); 5 //1.5 版本之前的写法; Integer i = 4; // 自动装箱 ,5 1.5 版本后的写法; i = i + 5; //i 对象是不能直接和 5 相加的,其实底层先将 i 转成 int 类型,在和 5 相加。而转成 int 类型的操作是隐 式的。 自动拆箱:拆箱的原理就是 i.intValue();i+5 运算完是一个 int 整数。 ~~~ ### 集合框架 1:对象封装数据,对象多了也需要存储。 集合用于存储对象。 2:对象的个数确定可以使用数组,但是不确定怎么办?可以用集合。因为 ### List接口 ~~~ List : 有序( ( 元素存入集合的顺序和取出的顺序一致) ) ,元素都有索引。元素可以重复。 | | -- ArrayList : 底层的数据结构 是数组, , 线程不同步 ,A At rrayList 了 替代了 Vector , 查询元素的速 度非常快。 | | -- LinkedList : 底层的数据结构是链表 , 线程不同步 , 增删元素的速度非常快。 | | -- Vector : 底层的数据结构就是数组 , 线程同步的 ,r Vector 无论查询和增删都巨慢。 ~~~ 对于 t list 集合,底层判断元素是否相同,其实用的是元素自身的 s equals 方法完成的。所以建议 元素都要复写 s equals ~~~ LinkedList : 的特有方法。 addFirst(); addLast(); 在 jdk1.6 以后。 offerFirst(); offerLast(); getFirst():获取链表中的第一个元素。如果链表为空,抛出 NoSuchElementException; getLast(); 在 jdk1.6 以后。 peekFirst();获取链表中的第一个元素。如果链表为空,返回 null。 peekLast(); removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出 NoSuchElementException removeLast(); 在 jdk1.6 以后。 pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回 null。 pollLast(); ~~~ ### Set接口 当元素的 hashCode 值相同时,才继续判断元素的 equals 是否为 true。 ~~~ TreeSet: 用于对 Set 集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。 如果元素不具备比较性,在运行时会发生 n ClassCastException 异常。 所以需要元素 实现 e Comparable 接口,强制让元素具备比较性, 复写 o compareTo 方法。 ~~~ ### Map集合 – Hashtable :底层是哈希表数据结构,是线程同步的。不可以存储 null 键,null 值。 – HashMap :底层是哈希表数据结构,是线程不同步的。可以存储 null 键,null 值。替代了 Hashtable. – TreeMap :底层是二叉树结构,可以对 map 集合中的键进行指定顺序的排序。 ### 把 把 p map 集合转成 t set 的方法 Set keySet(); Set entrySet(); //取的是键和值的映射关系。 ~~~ 取出 p map 集合中所有元素的方式一 : keySet() 方法。 可以将 map 集合中的键都取出存放到 set 集合中。对 set 集合进行迭代。迭代完成,再通过 get 方法对获取 到的键进行值的获取。 Set keySet = map.keySet(); Iterator it = keySet.iterator(); w w hile(it.hasNext()) { { Object key = it.next(); Object value = map.get(key); System.out.println(key+":"+value); } } 取出 p map 集合中所有元素的方式 二 : entry Set() 方法。 Set entrySet = map.entrySet(); Iterator it = entrySet.iterator(); while(it.hasNext()) { Map.Entry me = (Map.Entry)it.next(); System.out.println(me. getKey()+"::::"+me. getValue()); ~~~ ### 使用集合的技巧: ~~~ 看到 Array 就是数组结构,有角标,查询速度很快。 看到 link 就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast(); 看到 hash 就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖 hashCode,equals 方法。 看到 tree 就是二叉树,就要想到排序,就想要用到比较。 比较的两种方式 : 一个是 Comparable : 覆盖 o compareTo 方法 ; 一个是 Comparator : 覆盖 e compare 方法。 LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。 集合什么时候用? 当存储的是一个元素时,就用 Collection。当存储对象之间存在着映射关系时,就使用 Map 集合。 保证唯一,就用 Set 。不保证唯一 , 就用 List ~~~ ### 双列集合 Map ~~~ Map map = new HashMap(); map.put("a", "aaa"); // 传统方式:必须掌握这种方式 Set entrys = map.entrySet(); // 1.获得所有的键值对 Entry 对象 iter = entrys.iterator(); // 2.迭代出所有的 entry while(iter.hasNext()) { Map.Entry entry = (Entry) iter.next(); String key = (String) entry.getKey(); // 分别获得 key 和 value String value = (String) entry.getValue(); System.out.println(key + "=" + value); } ~~~ ### 泛型 当类中的操作的引用数据类型不确定的时候,以前用的 t Object 来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到的编译时期。 ~~~ class Tool<Q> { private Q obj; public void setObject(Q obj) { this.obj = obj; } public Q getObject() { return obj; } } ~~~ ### Data和日历类 将日期字符串转换成日期对象 :是 使用的就是 DateFormat 方法中的 Date parse(String source) ~~~ public static void method(){ Calendar c = Calendar.getInstance(); System.out.println(c.get(Calendar.YEAR)+"年"+(c.get(Calendar.MONTH)+1)+"月" +getNum(c.get(Calendar.DAY_OF_MONTH))+"日" +"星期"+getWeek(c.get(Calendar.DAY_OF_WEEK))); } public static String getNum(int num){ return num>9 ? num+"" : "0"+num; } public static String getWeek(int index){ /* 查表法:建立数据的对应关系. 最好:数据个数是确定的,而且有对应关系。如果对应关系的一方,是数字,而且可以作为角标,那么可以 通过数组来作为表。 */ String[] weeks = {"","日","一","二","三","四","五","六"}; return weeks[index]; } ~~~