接口
1.定义
java单继承性原因:避免继承的多个类中有相同定义的方法名称导致二义性。
接口的存在是为了多实现,克服java单继承的缺点。而接口与类的区别如下:
- 类中成员可分为public,private和proteced,而接口默认全为public
- 类中的方法可以声明并定义,而接口的方法只能声明,注意,接口的静态方法也可以直接声明定义
- 类中可以定义变量而接口只能定义常量
2.接口的声明与实现
1.接口的声明只需interface,示例如下:
interface Printable {
final int MAX=100; //public final int
void add(); //public abstract void add
float sum(float x ,float y);//public abstract float..
}
2.实现接口用implements关键字,一个类支持实现多接口,不同的类也可以实现一个接口,示例如下:
class A implements interfaceA,interfaceB //一个类多实现接口
class C implements interfaceA //多个类实现同一个接口
3.接口变量做参数回调
1.首先声明接口,一个文件只能定义一个与文件名相同的接口:
4.接口回调
形参为接口对象,实参为类实例,将类实例赋值给接口对象,通过回调实现函数的调用:
接口的默认方法
接口里可以声明默认方法,该方法可以在接口里直接实现,实现接口的类不需要对它进行重写:
public interface A{
void method();
default methodDefault(){
system.out.println("这是默认方法");
}
}
接口的私有方法
接口的私有方法
3.接口的一些注意事项
- 接口中定义的静态方法不能通过实现接口的类的对象调用,而只能通过接口名直接调用
-
对象的一些注意事项
1.在创建一个对象,使用构造函数new一个对象时,先在堆区分配内存放置对象的成员变量,和成员方法的地址,在方法区放置方法的声明,当调用方法或者定义方法时,在栈区开辟内存存放。
对象数组
对象数组,就是为对象类型的数组,数组元素存放的是对象的地址值,使用方法如下:
Person[] array = new Person[3];
array[0]=new Person("Tom"); //地址
array[1]=new Person("Jack"); //地址
array[2]=new Person("marial"); //地址
System.out.println(array[0].getName()); //将会打印Tom
ArrayList
ArrayList类似于动态数组,是java的一个封装类,可以实现长度的随意变化。
ArrayList的使用
1.声明ArrayList对象
首先要导入java.util.ArrayList的包
ArrayList <String> list = new ArrayList<>(); //尖括号内是list的数据类型,要求为泛型
2.ArrayList的增加和删除数据,查找数据
使用ArrayList类的add,remove和get方法可以实现数据的增删,查找
//增加数据
list.add("Tom");
System.out.println(list); //输出[Tom]
list.add("jack");
list.add("james");
System.out.println(list); //输出[Tom,jack,james]
//查找数据
String name = list.get(2); //索引从0开始,name为james
//删除数据
list.remove(2); //将会删除第三个元素,即删除james
System.out.println(list) //打印[Tom,jack]
3.获取ArrayList的长度
使用size()方法可以返回List的长度
int size = list.size(); //size为2,因为前面删除了一个元素
4.ArrayList的对象类型
ArrayList的泛型也支持自己写的类,假如我已经写好了Student类
ArrayList <Student> list = new ArrayList<>();
Student one = new Student("stu1");
Student two = new Student("stu2");
list.add(one);
list.add(two);
//使用list当中的对象
Student s1 = list.get(0);
String name = s1.getName(); //name为stu1
ArrayList的注意事项
- 声明ArrayList时尖括号内必须为泛型,泛型只能为引用类型,而不能是基本数据类型如int之类的,所以想使用基本数据类型,必须使用基本数据类型对应的包装类
字符串
字符串的3种创建方法
1.直接创建
String str1 = "Tom";
2.根据字符数组创建
char ch[]={'A','B','C'};
String str2 = new String(ch); //str2="ABC"
3.根据字节数组创建
byte by[] = {97,98,99};
String str3 = new String(by); //str3="abc"
4.不赋值将创建空字符串
String str4 = new String(); //str4为空字符串
字符串的一些方法
1.equals(String str)方法
使用equals方法将会比较字符串的内容,不会比较地址
String str1="hello";
char ch[]={'h','e','l','l','o'};
String str2=new String(ch);
str1.equals(str2); //将会返回true
str1.equals("hello"); //返回true
"hello".equals(str2); //返回true
2.equalsIgnoreCase(String str)方法
使用这个方法将会忽略字符串的大小写进行比较
String str1="Hello";
char ch[]={'h','e','l','l','o'};
String str2=new String(ch);
str1.equals(str2); //将会返回false
str1.equalsIgnoreCase(str2) //返回true
3.concat(String str)方法
使用concat方法可以拼接2个字符串,原字符串不变
String str1="hello";
String str2="world";
String str3=str1.concat(str2); //str3为helloworld
3.charAt(int index)方法
charAt方法可以找出字符串任何位置的字符,如果索引不合法将会出现异常
String str1="hello";
char ch = str1.charAt(1); //ch为e
4.indexOf(String str)方法
indexOf方法可以返回str在字符串中出现的第一个位置,没有将会返回-1
String str = "helloworld";
int index=str.indexOf("llo"); //index为2
5.subString(int index1,int index2)方法
subString方法可以获取原字符串从index1到index2-1的字串,如果只有一个参数,将默认index2为字符串的length
String str = "helloworld";
String str1=str.subString(5); //str1为world
String str2=str.subString(4,7); //str2为owo
6.toCharArray()方法
toCharArray方法可以将字符串变成字符数组
String str="hello";
char ch[]=str.toCharArray(); //ch[]={'h','e','l','l','o'}
7.replace(String str1,String str2)方法
replace方法可以将字符串里值为str1的字符串替换成str2
String str="hello";
String str1=str.replace("l","#"); //str1为he##o
String str2=str.replace("el",""ss"); //str2为hsslo
8.split(char ch)方法
split方法将会将字符串在ch处切割开成String数组,支持ch为空格
String str="aaa,bbb,ccc";
String s[]=str.split(","); //s[]={"aaa","bbb","ccc"}
字符串的注意事项
- 字符串是常量
- 字符串相当于char[]数组,但是在计算机底层是用byte[]数组实现的,因为字符使用ascii编码,在计算机底层翻译成数字储存在字节数组中
- 当使用String直接赋值创建多个值相同的字符串时,实际上这几个字符串共用字符串常量池,即共用1个地址
- new出来的String字符串不在常量池中,所以new出来的字符串即使只相同地址也不同
- 使用==比较时,基本数据类型比较的是值,而其他的比较的是地址
关于static
- static是修饰类静态成员的关键字,而静态成员是直接属于类的,即使用类名可以直接调用静态成员,同时,它属于类的成员,也可以使用对象进行调用
- 静态成员可以不创建对象而直接通过类调用
- 在类的内部,静态成员可以直接使用省略前面的类名或者对象名
- 静态方法不可以调用非静态成员
public class Test {
public static void main(String[] args) {
StaticDemo sd = new StaticDemo();
StaticDemo.staticMethod();
System.out.println(StaticDemo.count);
System.out.println(sd.count);
method1();
// method2(); //会报错
System.out.println((staticNum));
Test t=new Test();
System.out.println((t.num));
}
static int staticNum=0;
int num=1;
public static void method1()
{
System.out.println("method1");
}
public void method2()
{
System.out.println("method2");
}
}
-
静态方法的执行优先于非静态方法
-
静态代码块用于对静态成员的一次性赋值,静态代码块只执行一次,无论创建多少个对象都只执行一次,用法为:
static{ //静态代码块 }
Arrays类
Arrays类在java.util.Arrays包中,是对数组的辅助工具类
1.Arrays.toString()
toString方法可以将数组变成字符串形式
int[] arr1={1,2,3};
String StrArr1=Arrays.toString(arr1);
System.out.println(Array.toString(strArr1)); //输出[1,2,3]
2.Arrays.sort()
sort方法可以对数组进行升序排序,如果是数字则从小到大排列,如果是字母则按首字母字典序顺序排列
String[] strArr={"aaa","ccc","dd","bbb"};
Arrays.sort(strArr);
System.out.println(Arrays.toString(strArr)); //输出[aaa,bbb,ccc,dd]
3.toCharArray()
toCharArray方法可以将字符串转变为字符数组,用法为:Char []chStr=字符串名.toCharArray();
math类
math类在java.util.Math包中,提供了许多有数学运算相关的方法
1.abs()方法
使用Math.abs(double num)可以获得num的绝对值,但是num本身不变
2.ceil()方法
Math.ceil(double num)可以获取num的向上取整的浮点数,如num是3.1,则Math.ceil(3.1)为4.0
3.floor()方法
Math.floor(double num)方法为向下取整
4.round()方法
Math.round(double num)方法可以对num进行四舍五入取整
关于java的继承
- 子类可以直接访问父类所有的public成员,
- 当子类和父类有重名成员变量或方法时,通过对象调用该同名变量或方法,则先在该对象所在的类中寻找,若找不到则再向父类中寻找,这就是java的重写,可以通过在方法前加上@override检测是否合法重写
- 当子类和父类有成员方法用到了同名成员变量时,则调用该方法时,优先在该方法的类中寻找变量,没有再向父类寻找
- 关于类中的方法局部变量,成员变量和父类成员变量三者同名的调用:局部变量通过覆盖规则可以直接使用,本类成员变量则用this.变量名调用,父类变量用super.变量名调用
//father类定义了num=10
//son类如下:
public class son
{
int num=20;
void printNum()
{
int num=30;
system.out.println(num); //30
system.out.println(this.num); //20
system.out.println(super.num); //10
}
}
- 关于重写,只是方法的重写,而变量不能重写,
- 必须要求方法名称,参数列表相同,并且子类的返回类型小于或者等于父类的返回值类型,比如:
//父类方法为public object method();
//子类:
public string method(); //符合重写
//父类方法为public string method();
//子类:
public object method(); //不符合重写
- 重写的目的:在应用中,主要是在产品的更新换代中,每一个子类代表一代新产品,而子类直接继承功能不变的函数,而对需要升级的函数进行重写覆盖
- 对于构造方法:子类调用构造方法时必须调用父类的构造方法,且如果父类构造方法中有参数时,必须使用super关键字为父类构造方法传递实参
//父类
public class father {
public father(){
System.out.println("默认父类构造方法");
}
public father(int num){
System.out.println("重载子类构造方法"+num);
}
}
//子类
public class son extends father {
public son(){
System.out.println("默认子类构造方法");
}
public son(int num){
super(num);
System.out.println("重载子类构造方法");
}
}
//测试
son son1=new son(); //输出:默认父类构造方法 默认子类构造方法
son son2=new son(1); //输出:重载子类构造方法1 重载子类构造方法
- 构造方法之间可以相互调用,通过this()即可,但是构造方法中不能同时存在super()和this()
- 每次调用方法时,都是将方法区中的方法进栈
多态
- 使用父类对象创建子类引用时,是将子类当成父类使用,如把猫当成动物看,所以调用方法时优先调用子类的,若子类没有则向上寻找父类的
- 使用父类对象创建子类引用时,对象无法调用子类的变量
//父类
public class father {
int num=10;
public void showNum(){
System.out.println(num);
}
}
//子类
public class son extends father {
int num=20;
int age=30;
@Override
public void showNum(){
System.out.println(num);
}
}
//测试
public class Test {
public static void main(String[] args) {
father obj =new son();
System.out.println(obj.num); //父类变量10
// System.out.println(obj.age); //会报错
obj.showNum(); //优先调用子类方法
}
}
final关键字
- 使用final关键字修饰类时,该类不可以被继承,并且该类的成员不可以被重写覆盖,但是该类可以重写覆盖他的父类方法
- final关键字修饰的方法不能被覆盖重写
- abstract和final不能同时修饰一个方法
- 用final关键字修饰的变量不可以被改变,但是只声明用final修饰的变量,依然可以后续为该变量赋值,但赋值后就不可更改了
- 用final关键字修饰的对象其地址值不可改变,所以对该对象使用new方法重新分配内存空间会报错
访问权限
对于不同权限修饰符,不同的类,不同的包中访问权限有所差异:
内部类
(一)类中的内部类
在java中,类中可以定义另一个类,称为内部类,关于内部类有2种使用方法
1.在外部类的方法中调用内部类的方法成员,然后在main函数中调用该外部类方法间接调用内部类方法
2.直接调用: 外部类名称.内部类名称 对象名 = new 外部类().new 内部类();该对象可以直接调用内部类方法
(二)局部内部类,即方法里的内部类
在方法里定义的内部类,要想使用它,只能在局部方法里声明对象并对局部内部类的方法进行调用
匿名内部类
如果接口的实现类只需要使用唯一的一次,那么这种情况下就可以省略该实现类的定义,而改用使用匿名内部类,其定义格式为:
接口名称 对象名 = new 接口名称(){
//覆盖重写抽象方法
};
- 匿名内部类只能创建一个对象,因为它省略了【实现类/子类名称】,无法通过构造方法再次创建对象
- 匿名对象只能调用一次,一个方法,因为他省略了【对象名称】,无法再次通过对象名调用方法
注意事项
- 内部类可以使用外部类中的所有成员,包括private修饰的成员
- 在内部类中和外部类中有同名变量时,在内部类中,使用this指的是内部类对象,要使用外部类的成员变量,则需要使用外部类名.this.变量名
public outer{
public void method(){
int num=10; //等效final,因为没有改变
int num1=20;
num1=30; //发生了改变,不等效final
class inner{
System.out.println(num); //正确,输出10
System.out.println(num1); //将会报错
}
}
}
- 匿名内部类的对象可以作为方法的参数,匿名内部类的匿名对象也可以直接作为方法的参数:
// 定义了接口为Skill
// 定义了一个类Hero,Hero有一个方法为setSkill(Skill skill){}
//使用匿名内部类的匿名对象
Hero hero = new Hero();
hero.setSkill(new Skill(){
@override
public void use(){
System.out.println("use skill");
}
})
Object的一些方法
toString()方法
toString方法是Object类中的一个方法,返回值为字符串,而Object类是所有类的父类,所以toString方法可以供所有对象调用,一般来说,是在类中重写toString方法方便一些操作:
public class test {
private String name = "tom";
private int age = 10;
private boolean married = false;
@Override
public String toString() {
return "test{" +
"name='" + name + '\'' +
", age=" + age +
", married=" + married +
'}';
}
public static void main(String[] args) {
test t =new test();
System.out.println(t);
//输出结果为:test{name:'tom',age:'10',married:'false'}
}
}
- 一般来说,没有重写toString方法的类,其对象调用toString方法会返回对象的地址值,否则,该类中一定重写了toString方法
- 只有对象能调用toString方法,而其他比如说int等基本类型不能
- 字符串的toString为原字符串,ArrayList的toString为[…],它们都对toString进行了重写
equals()方法
equals方法也是Object类的一个方法,返回值为bool类型,基本格式为:
1.obj1.equals(obj2); //比较obj1和obj2的地址值
2.Object.equals(obj1,obj2); //另一种形式
- 同样的,一般我们使用equals()都要对其进行重写,例如String就对equals方法进行了重写,所以String字符串使用equals方法比较的是字符串内容而不是地址值
- null是不能调用方法的,所以使用null.equals(obj)方法将会出现空指针异常,所以我们对字符串使用equals方法时,最好使用第二种形式,防止字符串为空调用方法而抛出空指针异常
Date类
-
Date类位于java.util.Date包下,是与时间相关的一个工具类,Date的构造方法的常见重载形式有2种:
1.无参数的构造方法
无参数的Date构造方法将会获取当前的系统时间Date date = new Date(); //获取系统的当前时间
2.有参数的构造方法
有参数的Data构造方法中,其参数应为long类型的数,代表毫秒值,获取从初始时间后的多少毫秒之后的时间
Date date = new Date(long num); //获取从1970年1月1日0分0秒之后的num毫秒的时间
- getTime函数
getTime()函数用于返回调用的Data对象距离初始时间1970年的时间,返回值是毫秒值
Date date = new Date();
long time = date.getTime(); //time=1605524769466
Date的格式化和格式化的日期转换
DateFormat类是一个抽象类,我们不能直接使用,而SimpleDateFormat类是DateFormat类的一个实现子类,我们可以直接使用来对日期进行格式化,simpleDateFormat类的构造方法使用了类似于正则表达式的模式匹配,用不同的模式来构造出不同的日期格式,具体如下图所示:
- format方法:对日期进行格式化
Date date = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String text1 = sdf1.format(date);
String text2 = sdf2.format(date);
System.out.println(date); //Mon Nov 16 19:28:06 CST 2020
System.out.println(text1); //2020-11-16 19:28:06
System.out.println(text2); //2020年11月16日 19时31分56秒
- parse方法,还原格式化的日期
parse方法将格式化的日期文本还原为日期形式,它声明了一个异常ParseException,当模式与日期文本不匹配时抛出异常,所以在使用时一定要声明异常或者使用try,catch自己解决异常
public static void parseDemo() throws ParseException{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
Date date = new Date(); //Mon Nov 16 19:47:37 CST 2020
String text = sdf.format(date); //2020年11月16日 19时47分37秒
Date date1 = sdf.parse(text);
System.out.println(date1); //Mon Nov 16 19:47:37 CST 2020
}
StringBuilder类
StringBuilder类是对字符串进行操作的一个工具类,使用StringBuilder类的好处是方便,节省空间:因为String类的底层是final修饰的字符数组,所以导致了字符串的不可改变,而StringBuilder类的底层是没有final修饰的字符数组,所以它可变。
- delete(int start,int end)方法
delete方法用于删除StringBuilder对象的从start到end-1之间的内容,返回值也是this:
StringBuilder sb = new StringBuilder();
sb.apend("abc"); //sb="abc"
sb.delete(1,2);
System.out.println(sb); //sb="ac"
- reverse()方法
reverse方法可以将StringBuilder对象的内容反转
StringBuilder sb = new StringBuilder("abc");
sb.reverse(); //sb=cba
- toString()方法
toString方法可以将StringBuilder对象转换为String对象:
StringBuilder sb = new StringBuilder();
String str = sb.toString();
包装类
包装类就是把8种基本的数据类型封装到类中进行操作,下面以Interger为例说明:
装箱与拆箱
- 装箱:装修就是把基本数据类型转换为包装类的对象
Integer类就是对int数据类型的封装,其构造方法如下:
1.Interger in1 = new Interger(1); //参数为int类型
2.Interger in2 = new Interger(“1”); //参数为字符串类型,字符串类型的内容必须为int类型
在使用IDEA时用Interger的构造方法时,会发现Interger上会有一条横线,这代表这这个方法已经过时,不建议使用,所以相比于构造方法,还有2个静态方法生成Interger对象,效果等同于构造方法:
1.Interger in3 = Interger.valueOf(1);
2.Interger in4 = Interger.valueOf(“1”); - 拆箱:拆箱就是把包装类的对象转换为基本数据类型
interger in1 = new Interger(1); //装箱
int i = in1.intValue(); //拆箱
自动装箱与拆箱
自动装箱与拆箱就是自动将包装类对象和基本数据类型进行转换,Interger类的构造方法过时的原因就是jdk的新特性:自动装箱与拆箱
- 自动装箱
自动装箱就是省略了构造方法来将基本数据类型转为包装类对象,eg:
Interger in = 1; - 自动拆箱
自动拆箱就是将包装类对象转为基本数据类型,eg:
Interger in = 1;
in = in + 1;
字符串转变为其他基本数据类型
将其他类型转变为字符串有toString方法和valueOf方法,而将字符串转变为其他数据类型有parseInt,parseDouble等方法,使用方法为:
String str = "100";
int i = Interger.parseInt(str); //i=100
注意事项:
- 转变为其他数据类型的字符串的内容必须和转变的基本数据类型相同
- 使用parseInt只能由Interger调用,并且只能赋值给int变量,其他数据类型同理