1.构造方法可以在给对象初始化的时候给对象属性赋值,完成对象的初始化
2.使用new运算符时调用构造函数
3.为防止缺省构造器丢失,需手动写出缺省构造方法
4.实例变量的初始化不是类加载时完成,而是在产生对象进行
JVM中主要的三块内存空间:
1.栈内存:局部变量+方法空间
2.堆内存:存放对象
3.方法区内存:字节码文件(classloader将字节码文件装载到JVM中)
this指针就是一个指向本对象的指针
this.属性 访问的是自己的属性、
this() 调用自己的无参构造方法
1.this是一个关键字,是一个引用,保存内存地址并指向自身。
2.this可以使用在实例方法中,也可以使用在构造方法中。
3.this出现在实力方法中代表的是当前对象。
4.this不能出现在静态方法中。
5.this. 大部分可以省略,但是用来区分局部变量和实例变量时不能省略
6.this()这种语法只能出现在构造方法第一行,在无参构造方法中可以用this(参数)来调用有参构造函数,这样节省了重复代码。this()---->作用:代码复用
7.this内存图解:
1.方法覆盖:方法重写(Overrider、Overwrite)
2.子类对父类继承过来的方法进行方法覆盖之后,子类对象调用该方法时,一定执行覆盖之后的方法
3.形成方法覆盖条件:
(1)两个类有继承关系
(2)重写方法必须与之前方法具有相同的(返回值类型、方法名、形参列表)
(3)访问权限不能更低,可以更高
(4)重写之后的方法不可以抛出更多的异常,可以更少
4.注意事项:
(1)方法覆盖针对方法,和属性无关
(2)私有方法无法覆盖
(3)构造方法无法被继承,所以无从谈起方法覆盖
(4)方法覆盖只针对“实例方法”,“静态方法覆盖”不存在(静态方法执行与对象无关,子类“覆盖”之后还是会执行父类的静态方法)
5.Object类中toString()方法覆盖
(1)toString作用:将“java对象”转换成“字符串形式”
(2)toString原默认方法体:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
(3)toString方法覆盖(重写一定要复制粘贴)
public String toString() {
return year + "年" + month + "月" + day + "日";
}
6.方法重载和方法覆盖的异同
(1)方法重载发生在同一个类中;方法覆盖发生在两个有继承关系的类中
(2)方法重载是方法名相同,参数列表不同;方法覆盖是方法名相同,参数列表相同
一、基础语法
1.两个重要概念
向上转型(upcasting):子—>父 (自动类型转换) 向下转型(downcasting):父—>子 (强制类型转换)
无论是向上转型还是向下转型,两个类型之间必须有继承关系
2.允许父类型引用指向子类型对象
Animal animal = new Cat();
3.多态解释:编译时一种形态,运行时一种形态
java程序分为编译阶段和运行阶段
编译阶段:对于编译器来说只知道animal的类型是Animal,所以编译器在检查语法时会去Animal.class文件里寻找方法,字节码文件中若找到方法,便会绑定方法,编译通过,静态绑定成功。(编译阶段属于静态绑定)
运行阶段:堆内存中创建的对象时Cat对象,所以执行方法时,真正参与方法执行的是子类对象,所以运行阶段会动态执行子类对象的方法,这个过程属于运行阶段绑定。(运行阶段绑定属于动态绑定)
若执行的方法是子类特有的方法则无法通过编译阶段(在父类的class文件中找不到该方法—>语法不合法)
向下转型(强转)就可访问子类特有的方法
Cat cat = (Cat)animal;
4.运行时异常:java.lang.ClassCastException---->类转换异常(向下转型的风险)
二、开发中的作用
1.降低程序耦合度,提高程序扩展力:面向父类型编程、面向抽象编程
软件开发原则:对扩展开放,对修改关闭—>目的是降低耦合度提高扩展力
1.避免运行时异常:类转换异常
2.运行阶段动态判断:引用指向的对象的类型
3.返回值为Boolean(true/false)
4.animal instanceof Animal ----> true
5.用法:对类型向下转型时,使用instanceof运算符进行判断,可以避免ClassCastException
super与this关键字的比较
1.final是关键字,代表"最终的,不可变的"
2.修饰变量—>只能赋值一次
修饰方法—>无法被方法覆盖or方法重写
修饰类—>该类无法被继承
修饰对象引用—>其指向不可修改,但是对象内部数据可以修改
3.final修饰的实例变量一般添加static修饰并且访问权限都是public—>public static final联合修饰称为"常量"
4.常量和静态变量一样都是存储在方法区,都是在类加载时初始化,区别在于常量不可变,静态变量可变
1.概念:类与类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类,抽象类本身并不存在,所以无法创建对象进行实例化
2.抽象类属于引用数据类型
3.语法:
[修饰符列表] abstract class 类名{
类体;
}
4.final与abstract是对立的,无法同时使用
5.抽象类必须被继承,其子类也可以是抽象类,也可以是非抽象类
6.抽象类可以有构造方法供给子类使用
7.抽象方法:没有方法体的方法
例:public abstract void doSome();
8.抽象类中不一定有抽象方法,但是抽象方法必须位于抽象类中
9.抽象类的子类必须对抽象类中的抽象方法进行覆盖/重写/实现
面试题:java语言中凡是没有方法体的方法都是抽象方法?
答:错误的,native关键字修饰的方法就是底层调用C++写的动态链接库程序
例如:public native int hashCode();
10.抽象类并不完全抽象
1.接口是一种"引用数据类型"
2.接口是完全抽象的
3.接口定义语法:
[修饰符列表] interface 接口名{…}
4.接口可以继承,并且支持多继承,弥补了java中的类只支持单继承的缺陷
5.接口中只有:常量、抽象方法(不能有方法体)
6.接口中的所有元素都是public修饰
7.常量的public static final可以省略
抽象方法的public abstract可以省略
8.类与类之间称作继承(extends),类与接口之间称作实现(implements)
非抽象类实现接口时,必须将接口中的所有方法实现
9.一个类可以实现多个接口
10.extends和implements可以共存,extends在前
11.使用多态:接口类型引用指向子类型对象
12.接口A和接口B之间无继承关系,但是可以强制转换,编译可通过,但是运行可能会出现ClassCastException
13.接口在开发中的作用:
java中要求:面向抽象编程—>面向接口编程
接口使实现者与调用者解耦合
1.抽象类是半抽象的,接口是完全抽象的
2.抽象类中可有构造方法,接口中不可有构造方法
3.抽象类只能单继承,接口可以多继承
4.一个类只能继承一个抽象类,一个类可以实现多个接口
1.私有属性的set和get方法
set方法:在set中设立关卡可以防止用户的非法输入
public void set 属性名首字母大写(1个参数){
XXX = 参数;
}
get方法:
public int get 属性名首字母大写(){
return XXX;
}
2.接口都有调用者和实现者:面向接口调用、面向接口写实现类,这都属于面向接口编程
为什么要面向接口编程?
解耦合:降低程序耦合度,提高程序可扩展性
多态机制就是非常典型的面向抽象编程(不要面向具体编程)
建议:
Animal a = new Cat();
Animal b = new Dog();
//喂养方法
public void feed(Animal a){//面向父类型编程
}
不建议:
Dog d = new Dog();
Cat c = new Cat();
is-a: 继承关系(继承)----->Cat is a animal ---->A extends B
has-a: 属性关系(属性)—>I has a pen ---->A{B b;}
like-a: 实现关系(接口)—>Cooker like a FoodMenu ----> A implements B
public--------->表示公开的,在任何位置都可以访问
protected----->表示受保护,只能在本类、同包、子类中访问
default-------->表示默认的,只能在本类、同包中访问
private-------->表示私有的,只能在本类中访问
1.内部类:在类的内部又定义一个新的类,被称为内部类
2.分类:
静态内部类:类似于静态变量
实例内部类:类似于实例变量
局部内部类:类似与局部变量
3.内部类编写的代码可读性很差
1.数组是一种引用数据类型,父类是Object
2.数组中可以存储基本数据类型(内容),也可以存储引用数据类型(对象地址)
3.数组对象处于堆当中
4.数组一旦创建,在Java中规定:数组长度不可变
5.数组自带length属性,可以求数组长度
6.数组的优点、缺点、注意:
优点:检索效率高
缺点:随机增删效率较低,数据无法存储大数据量。
注意:数组最后一个元素的增删效率不受影响
7.数组是什么?(面试这样回答)
第一、空间存储上,内存地址是连续的
第二、每个元素占用的空间大小相同
第三、知道首元素的内存地址
第四、通过下标可以计算出偏移量
通过数组下标和数据类型可以计算出某一个元素的内存地址,效率很高
8.一、二维数组的静态初始化、动态初始化
静态初始化:
一维:
int[] arr = {1, 2, 3};
Object[] objs = { new Object(), new Object(), new Object() };
二维:
int[][] arr = {
{1, 2, 3},
{1, 2, 2, 5},
{2, 5, 9, 6, 3}
};
Object[][] objs = {
{new Object(), new Object(), new Object() },
{new Object(), new Object()},
{new Object()}
};
动态初始化:
一维:
int[] arr = new int[4]; //4个长度,每个元素默认为0
Object[] objs = new Object[4]; //4个长度,每个元素默认值为null
二维:
int[][] arr =new int[3][4];
Object[][] arr = new Object[4][4];
Animal[][] animal = new Animal[3][4];
//既可以存储Animal对象,也可以存储Animal的子类对象
9.一维数组的遍历:
一维:
for( int i = 0; i < arr.length; i++){
System.out.println( arr[i] );
}
二维:
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.print(arr[i][j]);
}
System.out.println();
}
10.main方法上"String[] args"参数:运行程序之前需要输入的字符串,可以用来判断是否具有使用该程序的权限
11.数组的拷贝:String.arraycopy()方法的使用
数组有一个特点:长度一旦确定,不可变
所以数组长度不够时,需要扩容,扩容的机制是:新建一个大数据,将小数组中的数据拷贝到大数组,然后小数组对象被垃圾回收
12.数组内存结构:
1.字符串的动态创建、静态创建
动态创建:String str = new String(" abc "); ----->垃圾回收器会回收
静态创建:String str = " abc "; ----->垃圾回收器不会回收
2.字符串的存储位置
动态创建:字符串引用位于栈中(存储字符串对象的地址),字符串对象位于堆中(存储字符串内容的地址),字符串内容位于方法区中的字符串常量池中
静态创建:字符串引用位于栈中(存储字符串对象的地址),字符串内容位于方法区中的字符串常量池中
3.静动态创建相同字符串的异同
静态创建:str1和str2中存储的地址一模一样,都是位于字符串常量池中"abc"的地址。
String str1 = "abc";
String str2 = "abc";
动态创建:str1和str2中存储的地址不一样,分别是位于堆上的不同字符串对象
String str1 = new("abc");
String str2 = new("abc");
4.字符串内容比较使用:equals()方法
例如:
str1.equals(str2);
"hello".equals(str1); --->可以避免空指针异常
5.面试题:
String str1 = new("abc");
String str2 = new("abc");
一共产生了3个对象:字符串常量池中一个,堆上两个String对象
第一个:String s = new String("");
第二个:String s = “”;
第三个:String s = new String(char 数组);
第四个:String s = new String(char 数组,起始下标,长度);
第五个:String s = new String(byte数组);
第六个:String s = new String(byte数组,起始下标,长度);
1、(掌握)char charAt( int index )
作用:获取指定位置字符
char c = "中国人".charAt(1);
System.out.println(c);//国
2、(了解)int compareTo(String anotherString)
作用:比较字符串的大小
字符串之间比较大小不能直接使用 “<”">",需要使用compareTo方法。
int result = "abc".compareTo("abc");
System.out.println(result);
//0(等于0) 前后一致 10 - 10 = 0
int result2 = "abcd".compareTo("abce");
System.out.println(result2);
//-1(小于0) 前小后大 8 - 9 = -1
int result3 = "abce".compareTo("abcd");
System.out.println(result3);
// 1(大于0) 前大后小 9 - 8 = 1
// 拿着字符串第一个字母和后面字符串的第一个字母比较。能分胜负就不再比较了。
System.out.println("xyz".compareTo("yxz")); // -1
3、(掌握)boolean contains(CharSequence s)
作用:判断前面的字符串中是否包含后面的子字符串。
System.out.println("HelloWorld.java".contains(".java")); // true
System.out.println("http://www.baidu.com".contains("https://")); // false
4、(掌握) boolean endsWith(String suffix)
作用:判断当前字符串是否以某个子字符串结尾。
System.out.println("test.txt".endsWith(".java")); // false
System.out.println("test.txt".endsWith(".txt")); // true
System.out.println("fdsajklfhdkjlsahfjkdsahjklfdss".endsWith("ss")); // true
5、(掌握)boolean equals(Object anObject)
作用:比较两个字符串必须使用equals方法,不能使用“==”
equals只能看出相等不相等,
compareTo方法可以看出是否相等,并且同时还可以看出谁大谁小。
System.out.println("abc".equals("abc")); // true
6、(掌握)boolean equalsIgnoreCase(String anotherString)
作用:判断两个字符串是否相等,并且同时忽略大小写。
System.out.println("ABc".equalsIgnoreCase("abC")); // true
7、(掌握)byte[] getBytes()
作用:将字符串变成字节数组,数组中存放的是对应字符串中字符的数值,例如,a----97; b----98
byte[] bytes = "abcdef".getBytes();
for(int i = 0; i < bytes.length; i++){
System.out.println(bytes[i]);
}
//bytes[] = {97,98,99,100,101,102}
8、(掌握).int indexOf(String str)
作用:判断某个子字符串在当前字符串中第一次出现处的索引(下标)。
System.out.println("oraclejavac++.netc#phppythonjavaoraclec++".indexOf("java")); // 6
9、(掌握)boolean isEmpty()
作用:判断某个字符串是否为“空字符串”。底层源代码调用的应该是字符串的length()方法。
String s1 = "";
String s2 = "a";
System.out.println(s1.isEmpty());//true
System.out.println(s2.isEmpty());//false
10、(掌握) int length()
面试题:判断数组长度和判断字符串长度不一样
判断数组长度是length属性,判断字符串长度是length()方法。
System.out.println("abc".length()); // 3
System.out.println("".length()); // 0
11、(掌握)int lastIndexOf(String str)
作用:判断某个子字符串在当前字符串中最后一次出现的索引(下标)
System.out.println("oraclejavac++javac#phpjavapython".lastIndexOf("java")); //22
12、(掌握). String replace(CharSequence target, CharSequence replacement)
作用:将某段子字符串替换成另一个字符串替换
String的父接口就是:CharSequence
String newString = "http://www.baidu.com".replace("http://", "https://");
System.out.println(newString); //https://www.baidu.com
//把以下字符串中的“=”替换成“:”
String newString2 = "name=zhangsan&password=123&age=20".replace("=", ":");
System.out.println(newString2); //name:zhangsan&password:123&age:20
13、(掌握).String[] split(String regex)
作用:按照某个字符拆分字符串
String[] ymd = "1980-10-11".split("-"); //"1980-10-11"以"-"分隔符进行拆分。
for(int i = 0; i < ymd.length; i++){
System.out.println(ymd[i]);
}
String param = "name=zhangsan&password=123&age=20";
String[] params = param.split("&");
for(int i = 0; i <params.length; i++){
System.out.println(params[i]); // 可以继续向下拆分,可以通过“=”拆分。
}
14、(掌握)、boolean startsWith(String prefix)
作用:判断某个字符串是否以某个子字符串开始。
System.out.println("http://www.baidu.com".startsWith("http")); // true
System.out.println("http://www.baidu.com".startsWith("https")); // false
==15、(掌握)String substring(int beginIndex) ==
参数是起始下标
作用:从某一个位置开始截取后面字符串
System.out.println("http://www.baidu.com".substring(7)); //www.baidu.com
16、(掌握)String substring(int beginIndex, int endIndex)
作用:将某一段子字符串变变成新字符串
beginIndex起始位置(包括)
endIndex结束位置(不包括)
System.out.println("http://www.baidu.com".substring(7, 10)); //www
17、(掌握)char[] toCharArray()
作用:将字符串转换成char数组
char[] chars = "我是中国人".toCharArray();
for(int i = 0; i < chars.length; i++){
System.out.println(chars[i]);
}
//chars[] = {'我','是','中','国','人'}
18、(掌握)String toLowerCase()
作用:将字符串全部变成小写
System.out.println("ABCDefKXyz".toLowerCase());
//abcdefkxyz
19、(掌握)String toUpperCase();
作用:将字符串全部变成大写
System.out.println("ABCDefKXyz".toUpperCase());
//ABCDEFKXYZ
20、(掌握)String trim();
去除字符串前后空白
System.out.println(" hello world ".trim()); //hello world
21、(掌握) String中只有一个方法是静态的,不需要new对象
这个方法叫做valueOf,作用:将“非字符串”转换成“字符串”
String s1 = String.valueOf(true);
String s1 = String.valueOf(100);
String s1 = String.valueOf(3.14);·