1.2.1 类和对象
1、概念
Java中一切皆对象,一切围绕对象进行。
类:具有相同属性的一类对象抽象为类,如人类,犬类。
对象:某个类的一个实例,当有对象之后,属性才有属性值,行为也有了意义。
2、类的组成
1.属性
即成员变量,在类中定义的变量。public static String name;其中,public为访问修饰符;static为静态关键字;String为类型;name为变量名。
2.方法
构造方法:对对象初始化,构造出一个类的实例,构造方法和类名相同,没有返回值,没有void。分为无参构造和有参构造,在new时调用。
public static int getName(String name) 参数个数和类型不同,方法不同。返回值不影响。
方法重载: 同一个类中,方法名相同,参数的个数或类型不同,和返回值无关。
3、static和final
final:表示最终。修饰变量,局部变量只能赋值一次,实例变量系统不会给默认值,必须手动赋值;修饰方法,无法被继承;修饰引用,只能指向一个对象。
1.2.2 封装、继承、多态
1、封装
将类信息隐藏在内部,用户不能直接访问,通过提供的方法访问访问。
a.属性私有 b.set/get加控制语句
2、继承
只有构造方法不能被继承,子类调用父类构造方法需放在第一行。私有成员也可以被继承,只是不可见,如儿子继承父亲保险箱,没有密码。
3、多态
方法重写:根据需要重写父类方法。子类super调用父类方法。
重写规则:
a.返回值相同或者是其子类
b.访问权限不能严于父类
c.是否静态不能改变
d.私有方法不能重写
e.不能抛出超过父类异常
多态:同一引用类型,使用不同实例调用不同方法。
左侧:父类引用:编译类型 右侧:子类实例:执行类型
Persion per=new Student(); per.mission(); //父类引用类型调用子类方法
1.2.3 抽象类、接口
1、抽象类
使用abstract修饰的类。(如果一个类没有足够的信息来修饰一个对象,则此类为抽象类)抽象类不能被实例化,但可以有方法体。抽象方法是abstract修饰的方法,没有方法体,由子类实现。
2、接口
抽象方法的集合,没有属性和构造方法,严格意义上接口不是类。
抽象类和接口的区别:
a.抽象类有可以实现的方法,接口只有抽象方法。
b.子类关键字不同,接口 implements 抽象类 extends
c.抽象类有构造方法、属性,接口没有
d.接口不写abstract,且可以实现多个,继承只能继承一个
e.方法的访问修饰符不同,抽象类:default、protected、public 。接口:public。
3、内部类
一个类的内部完整的嵌套了另一个类的结构,被嵌套的类称为内部类,通常情况下内部类分为以下三种:
a.成员内部类
在类的成员变量位置编写的类,称为成员内部类。成员内部类可以访问类的所有非静态属性和方法。包括private修饰的方法,调用方式为 Outer.this.属性名。成员内部类可以使用四种修饰符。内部类依托于外部类而存在,即创建内部类需先创建外部类,方法如下:
Outer.Inner inner = new Outer().new Inner();
b.局部内部类
定义在方法里的类,局部内部类的访问权限仅在方法体内,同局部变量相同,局部内部类也不能使用权限修饰符,静态修饰符进行修饰。它可以直接访问方法中的变量和外部类的属性和方法。通过Outer.this.属性 调用
c.静态内部类
成员内部类多一个static,它不需依赖内部类,和静态属性类似,不能调用外部类的非静态成员,其内部可以声明静态和非静态属性。
int age = Outer.Inner.age;
4、匿名类
内部类中没有类名的类称为匿名类,其内部不能定义静态成员,通常跟在new后面,用于实现一个接口。通常在Lambda中,参数的传递通过匿名类完成。
Dao dao = new Dao() { @Override public int getAge() { return 0; } };
1.2.4 集合
在内存中申请一块空间存储数据,替换掉等长的数组。
1、List
有序、重复
实现类:ArrayList 查询快
LinkedList 增删快 独有方法:add/get/remove First/Last
Vector 线程安全
2、Set
无需、不重
实现类 HashSet hash表存储,通过hashCode()和equals()方法确保唯一性。先判hashCode() 若相同 再判equals() 相同则为同一对象。
LinkedHashSet 链表+hash表 有序、唯一
TreeSet 二叉树 唯一,排好序 自然排序:元素实现Comparable接口,并重写CompareTo方法,若compareTo返回本对象大于输入,则为顺序排序,相同为同一对象;构造器排序,Tree构造方法传入构造器Comparator实现类,重写compare方法。
3、Map
用于保存映射关系的数据,map没有实现Collection接口。
实现类 HashMap 可存一个null key,用作key的引用需有hashCode和equals方法
HashTable 线程安全,key和value均不可存入空值
TreeMap 基于红黑树,对key排序,排序方式和Set相同
4、底层逻辑
Array... 底层数组 查询快、增删慢
Linked... 底层链表 查询慢、增删快
Hash... 底层哈希表 依赖hashCode和equals
Tree... 底层二叉树 有序,依赖自然排序或构造器排序
5、iterator
iterator-迭代器是集合固有的遍历方式,Collection实现类都有,效率高于fori,调用next后,指针才指向下一个元素。
增强for底层也是iterator,现实现法如下:
Iterator<Integer> iterator = integers.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); }
6、properties
properties是一个Map,key和value都是String,被称为属性类对象。
7、泛型
将类型参数化,将数据类型设置为一个参数,分为:泛型类、泛型方法、泛型属性。
8、枚举
所有枚举类都是Enum子类,有以下方法:
a.int CompareTo 返回声明顺序差
b.String name
c.int ordinal 声明序号
d.static Enum valueOf 根据字符串返回枚举值
public enum Level { one,two,three }
1.2.5 常用实用类
1、String
split | str,i | String[] | 按str拆分,拆成i个元素,后面放在一个元素 |
equalsIgnoreCase | str | boolean | 不计大小写相等 |
charAt | i | char | 返回i下表字符 |
compareTo | str | int | 第一个不同字符ASC码差 |
concat | str | boolean | 拼接 |
contentEquals | str/strBuffer | boolean | 相等,可判别不同类型 |
getbytes | byte[] | 返回对应字符ASC码数组 | |
getChars | int,int,char[],int | 字符串前两个参数下表的字符放到char数组 | |
index | char,str | int | 第一个匹配的字符或匹配到字符串的第一个字符下标 |
intern | 引用指向常量池 | ||
startWith | str,int | boolean | 第i个下标是否以str开始 |
replaceFirst | str1,str2 | string | 第一次出现的str1替换成str2 |
substring | int1,int2 | string | 剪切,左包右不包 |
toCharArray | char[] | char数组 | |
tolower/upperCase | string | 转大小写 | |
trim | string | 去除两侧空格 | |
contain | str | boolean | 包含 |
2、Math
max 最大值;min 最小值;abs 绝对值;round 四舍五入;ceil 向上舍入;floor 向下舍入;pow 幂;sqrt 开方;radom (0,1)随机数
3、System
arrayCopy | int[],int1,int[],int2,int3 | 数值值复制,int1为原数组起始下标;int2为新数组起始下标;int3复制几个元素 |
currentTimeMills | 当前时间戳 |
4、date
构造 new Date();本地当前时间
new Date(时间戳);
常用方法 getTime();返回时间戳。compareTo 两个日期顺序
5、calender
Calender是一个抽象类,初始化:Calender.getInstance();
setTime | date | 赋值时间 | |
getTime | date | 获取时间 | |
add | Calender.Month,3 | 月+3 | |
after/before | calender | boolean | 比较 |
6、simpleDateFormat
初始化:new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
parse | string | date |
format | date | string |
7、Object
所有类的超类,常用方法hashCode、finalize垃圾回收
8、Optional
Optional本质是个容器,包装原有类,以避免空值异常。
创建:Optional.of(t) t非空对象
isPresemt | boolean | 是否有值 | |
get | T | 有则返回,无报异常 | |
orElse | N | T | 有则返回T,无返回N |
1.2.6 JVM
1、JVM内存划分
a.寄存器和本地方法栈:CPU或JVM使用,与开发无关。
b.方法区:存储可运行的.class文件,静态变量,常量等。
c.堆:对象或数组,堆存放的数据都有一个地址值存在栈中,且这些数据都有默认值。
d.栈:方法运行时使用的内存,用于存放方法中的局部变量。
2、常量池
静态常量池:文件被JVM加载后存放各种字面量和符号引用,即Java中的常量和类名、方法名。又叫class文件常量文件池。在方法区中
文本字符串
字面量 声明为final的常量
静态常量池: 基本数据类型
类和结构完全限量名
符号引用 字段名和描述符
方法名和描述符
运行常量池 class加载后 静态常量池 ->运行常量池 也在方法区中
字符串常量池 为提升性能,减少开销 在堆中
总结:全局字符串常量池在每个VM中只有一份,存放字符串常量池引用值。class常量池在编译时,每个class都有,用于存放常量符号引用。类加载完成后,符号引用替换为直接引用,和全局常量池引用一致。
3、类加载过程
类加载的过程是JVM把.class文件类信息加载进内存,并解析成对应class对象的过程,Java并非一开始加载所有类,而是在遇到某个类时才会加载。
加载过程如下
a.通过类的全名获取类的二进制流。
b.解析二进制流为方法区的数据结构。
c.创建java.lang.Class实例,作为方法区这个类的数据访问入口
4、类加载器
用于完成类加载任务,分为Bootstrat加载器、ExtclassLoader和AppClassLoader
a.Bootstrat 用于加载jdk/jre/lib下的核心类库。
b.ExtClassloader 用于加载 jdk/jre/ext 下的拓展类库
c.AppClassLoader 用于加载classPath环境变量指定类库,是用户自定义类的默认加载器。
加载机制:双亲委托机制,先找父类,没有自己加载
类加载调用时机
a.创建实例
b.调用静态成员
c.初始化一个类的子类
d.反射
5、反射
无需new对象调用一个类的方法或属性(包括私有),通过创建class对象实现。
Class<?> user = Class.forName("org.example.User"); Class<?> superclass = user.getSuperclass();
获得class对象方法
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); Class<?> user1 = systemClassLoader.loadClass("org.example.User"); Class<User> userClass = User.class; Class<?> user = Class.forName("org.example.User");//类名务必写全名
反射调用属性
Class<?> user = Class.forName("org.example.User");//创建class对象 Field name = user.getDeclaredField("name");//获得属性对象 name.setAccessible(true);//开放权限 Object o = user.newInstance();//反射获得实例 name.set(o,"jack");//属性赋值 Object o1 = name.get(o); System.out.println(o1);
反射调用方法
Class<?> aClass = Class.forName("org.example.User"); Method setName = aClass.getDeclaredMethod("setName",String.class); Method setAll = aClass.getDeclaredMethod("setAll",String.class,int.class); Method getName = aClass.getDeclaredMethod("getName"); setName.setAccessible(true); setAll.setAccessible(true); getName.setAccessible(true); User o = (User) aClass.newInstance(); setName.invoke(o,"张三"); setAll.invoke(o,new Object[]{"张三",21}); Object invoke = getName.invoke(o, new Object[0]); System.out.println(invoke);