IDEA常用快捷键
| 快捷键 | 功能 |
|---|---|
| Alt+回车 | 导入包,自动修正 |
| Ctrl+N | 查找类 |
| Ctrl+Shift+N | 查找文件 |
| Ctrl+Alt+L | 格式化代码 |
| Ctrl+Alt+O | 优化导入的类和包 |
| Alt+Insert | 生成代码(如get,set方法,构造函数等) |
| Ctrl+E或者Alt+Shift+C | 最近更改的代码 |
| Ctrl+R | 替换文本 |
| Ctrl+F | 查找文本 |
| Ctrl+Shift+Space | 自动补全代码 |
| Ctrl+空格 | 代码提示 |
| Ctrl+Alt+Space | 类名或接口名提示 |
| Ctrl+P | 方法参数提示 |
| Ctrl+Shift+Alt+N | 查找类中的方法或变量 |
| Alt+Shift+C | 对比最近修改的代码 |
| Shift+F6 | 重构-重命名 |
| Ctrl+Shift | 先上键 |
| Ctrl+X | 删除行 |
| Ctrl+D | 复制行 |
| Ctrl+/ 或 Ctrl+Shift+/ | 注释(// 或者/…/ ) |
| Ctrl+J | 自动代码 |
| Ctrl+E | 最近打开的文件 |
| Ctrl+H | 显示类结构图 |
| Ctrl+Q | 显示注释文档 |
| Alt+F1 | 查找代码所在位置 |
| Alt+1 | 快速打开或隐藏工程面板 |
| Ctrl+Alt+ left/right | 返回至上次浏览的位置 |
| Alt+ left/right | 切换代码视图 |
| Alt+ Up/Down | 在方法间快速移动定位 |
| Ctrl+Shift+Up/Down | 代码向上/下移动。 |
| F2 或Shift+F2 | 高亮错误或警告快速定位 |
关闭当前项目
方法定义时注意事项:
1.方法应当定义在类当中,但是不能在方法中再定义方法,不能嵌套
2.方法定义的前后顺序无所谓
3.方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用
4.如果方法有返回值,那么必须写上“return 返回值”
5.return之后的返回值数据,必须和方法的返回值类型对应起来
6.对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己
7.对于void方法当中最后一行的return可以省略不写。
8.一个方法当中可以有多个return,但是要保证同时只有一个会被执行到,两个return不能连写。
方法的重载Overload
对于功能相似的方法,因为参数列表不同,写不同的方法名太过麻烦了,所以引入方法重载的概念。
多个方法的名称相同,但是参数列表不同。
方法重载与下列因素有关:
1.方法的参数个数不同
2.方法的参数类型不同
3.方法的参数多类型顺序不同
方法重载与下列因素无关:
1.与参数的名称无关
2.与方法的返回值类型无关
Java 的数组
数组的特点:
1.数组是一种引用数据类型
2.数组当中的多个数据,类型必须统一,跟JavaScript不同,JavaScript数组中数据的类型可以不同。
3.数组的长度在程序运行期间不可改变
数组的初始化,在内存当中创建一个数组,并且向其中赋予一些默认值
两种常见的初始化数组方式:
1.动态初始化(指定长度)
2.静态初始化(指定内容)
动态初始化数组格式:
数据类型【】 数组名称 = new 数据类型/数组长度
int[] arr1 = new int[300];
String[] arr2 = new String[5];
静态初始化数组格式:
数据类型【】 数组名称 = new 数据类型【】{元素1、元素2…}
int[] arr = new int[] {5,15,25};
String[] arr2 = new String[] {"hello","world","java"};
使用静态初始化时格式还可以省略一下
省略格式:数据类型【】 数组名称 = {元素1、元素2…}
注意事项:
1.静态初始化没有直接指定长度,但是仍然会自动推算得出长度
2.静态初始化标准格式可以拆分成为两个步骤
int[] arr1 = {10,20,30};
int[] arr2;
arr2 = new int[] {10,20,30};
使用初始化建议
如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。
访问数组元素的格式:
数组名称[索引值]
Java的内存需要划分为5个部分
1.栈(stack):存放的都是方法的局部变量。方法的运行一定要在栈当中运行。
局部变量:方法的参数,或者是方法()内部的变量
作用域:一旦超出作用域,立刻从栈内存当中消失
2.堆(heap):凡是new出来的东西,都在堆当中。堆内存里面的东西都有一个地址值:16进制。
堆内存里面的数据都有默认值。规则:
如果是整数 默认为0
如果是浮点数 默认为0.0
如果是字符 默认为’\u0000’
如果是布尔 默认为false
如果是引用类型 默认为null
3.方法区(Method Area):存储.class相关信息,包含方法的信息。
4.本地方法栈(Native Method Stack):与操作系统相关。
5.寄存器(pc Register):与CPU相关。
面向对象和面向过程
面向过程
当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。
面向对象
当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事儿。
类和对象
类
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。
现实中,描述一类事物:
- 属性:就是该事物的状态信息
- 行为:就是该事物能够做什么
举例:小猫
- 属性:名字,体重,年龄,颜色
- 行为:走,跑,叫
定义一个标准类
一个标准的类通常要拥有以下四个组成部分:
1.所有成员变量都要使用private关键字修饰
2.为每一个成员变量编写一对getter/setter方法
3.编写一个无参数的构造方法
4.编写一个全参数的构造方法
这样标准的类也叫做Java Bean
例子:
编写时写完变量可以直接生成getter和setter代码
public class Student {
private String name; //姓名
private int age; //年龄
//无参数构造方法
public Student() {
}
//全参数构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class DemoStudent {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("克苏鲁的呼唤");
stu1.setAge(20);
System.out.println("name: " + stu1.getName() + ",age:" + stu1.getAge());
System.out.println("=======================");
Student stu2 = new Student( "恩齐都", 21);
System.out.println("name: " + stu2.getName() + ",age:" + stu2.getAge());
}
}
效果:
对象
对象:是一类事物的具体体现。对象是类的一个实例,必须局部该类事物的属性和行为
类和对象的关系
- 类是对一类事物的描述,是抽象的
- 对象是一类事物的实例,是具体的
- 类是对象的模板,对象是类的实体
通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
1.导包,也就是指出需要使用的类在什么位置。
import 包名称.类名称
import cn.itcast.day1.demo1.Student
对于和当前类属于同一个包的情况,可以省略包语句不写
2.创建,格式:
类名称 对象名 = new 类名称();
Student stu = new Student();
3.使用分两种情况
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)
局部变量和成员变量不同
1.定义的位置不一样【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中
2.作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能使用了
成员变量:整个类全都可以通用
3.默认值不一样【重点】
局部变量:没有默认值,如果想要使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样
4.内存的位置不一样
局部变量:位于栈内存
成员变量:位于堆内存
5.生命周期不一样
局部变量:随着方法进栈而诞生,随着方法出栈而消失,存在时间要短一些。
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失。
当方法的局部变量和类的成员变量重名的时候,根据”就近原则“,优先使用局部变量。
如果需要访问本类当中的成员本来,需要使用格式:this.成员变量名
public class Testday1 {
//成员变量
String num = "123";
public void call(){
//局部变量
int n = 10;
System.out.println(n);
}
public static void main(String[] args) {
System.out.println(num);
call();
}
}
面向对象三大特征:封装、继承、多态
封装
1.方法就是一种封装
2.关键字private也是一种封装,一旦使用了private进行修饰,那么本类种仍然可以随意访问。但是超出了本类范围就不能再直接访问了。但可以间接访问。间接访问private成员变量,就是定义一对getter/setter方法,类似于JavaScript中的闭包。
对于getter来说,不能有参数,返回值类型和成员变量对应
对于setter来说,不能有返回值。参数类型和成员变量对应
public class Testday1 {
//成员变量
String name; //姓名
private int age; //年龄
public void show(){
System.out.println("My name is " + name + "and age is " + age);
}
//设置一个成员方法,专门用于向age设置数据
public void setAge(int num) {
age = num;
}
//这个成员方法专门用于获取age的数据
public int getAge() {
return age;
}
}
封装就是将一些细节信息隐藏起来,对于外界不可见
继承
继承是多态的前提,没有继承就没有多态
继承主要解决的问题就是:共性抽取
父类:也可以叫做基类
子类:也可以叫做派生类
在继承的关系中,子类就是一个父类,子类可以被当作父类来看待
定义父类的格式:(一个普通的类定义)
定义子类的格式:
public class 子类名称 extends 父类名称 {
}
//定义一个员工的子类,讲师
public class extendsDemo extends Employee{
}
//定义一个父类 员工
class Employee {
public void method(){
System.out.println("方法执行!");
}
}
在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接通过子类对象访问成员变量
- 间接通过成员方法访问成员变量,该方法属于谁,就优先用谁,没有则向上找。
访问成员变量:
- 局部变量: 直接写成员变量名
- 本类的成员本类名: this.成员变量名
- 父类的成员变量: super.成员变量名
继承关系中,父子类构造方法的访问特点:
- 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
- 可以通过super关键字来子类构造调用父类重载构造
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
public class extendsDemo extends Employee{
@Override //如果@Override没有报错,则证明重写正确
public void method(){
int a = super.a;
}
public extendsDemo(){
//super(); //在调用父类无参构造方法
super(20);
System.out.println("子类构造方法");
}
}
//定义一个父类
class Employee {
int a;
public void method(){
System.out.println("方法执行!");
}
public Employee(){
System.out.println("父类无参构造方法!");
}
public Employee(int num) {
System.out.println("父类有参构造方法!");
}
}
super关键字的用法有三种:
- 在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在本类的构造方法中,访问本类的另一个构造方法
class Zi extends Employee {
public Zi(){
this(123); //本类的无参构造调用本类的有参构造
}
public Zi(int n){
}
public Zi(int a,int b){
}
}
super和this的应用
public class FuZiDemo {
public static void main(String[] args) {
Zidemo zi = new Zidemo();
zi.method();
zi.show();
}
}
class Fu {
int num = 10;
public void method(){
System.out.println("父类方法");
}
}
class Zidemo extends Fu {
int num = 20;
@Override
public void method(){
System.out.println("子类方法");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num);
}
}
Java语言中的继承三个特点
方法的重写(Override)
概念:在继承关系中,方法的名称一样,参数列表也一样
可以使用@Override检查是否正确重写。
public class extendsDemo extends Employee{
@Override //如果@Override没有报错,则证明重写正确
public void method(){
}
}
//定义一个父类 员工
class Employee {
public void method(){
System.out.println("方法执行!");
}
}
注意事项:
- 必须保证父类子类之间的名称相同,参数列表也相同。
- 子类方法的返回值必须小于等于父类方法的返回值范围
- 子类方法的权限必须大于等于父类方法的权限修饰符
public > protected > (default) > private
备注:(default)不是关键字default,而是什么都不写,留空
设计原则
对于已经投入使用的类,尽量不要进行修改,推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新内容。
发红包练习
import java.util.ArrayList;
import java.util.Random;
public class SendHongbao {
public static void main(String[] args) {
//群主
Manager manager = new Manager("群主",100);
//三个群成员
Member one = new Member("成员1",0);
Member two = new Member("成员1",0);
Member three = new Member("成员1",0);
manager.show();
one.show();
two.show();
three.show();
System.out.println("***********************");
//群主发80圆,分三个红包
ArrayList<Integer> redList = manager.send(80,3);
//三个成员收红包
one.receive(redList);
two.receive(redList);
three.receive(redList);
manager.show(); //100 - 80 = 20
one.show();
two.show();
three.show();
}
}
class User{
private String name; //姓名
private int money; //余额,当前用户拥有的钱数
public User(){
}
public User(String name, int money) {
this.name = name;
this.money = money;
}
//展示一下当前用户有多少钱
public void show(){
System.out.println("我叫:" + name + ",我有:¥" + money);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
class Manager extends User{
public Manager(){
}
public Manager(String name, int money) {
super(name, money);
}
//发红包方法
public ArrayList<Integer> send(int totalMoney,int count){
//首先需要一个集合,用来存储若干个红包的金额
ArrayList<Integer> redList = new ArrayList<>();
//看一下群主自己有多少钱
int ownMoney = super.getMoney(); //群主当前余额
if(totalMoney > ownMoney){
System.out.println("余额不足");
return redList; //返回空集合
}
//扣钱,重新设置余额
super.setMoney(ownMoney - totalMoney);
//发红包需要平均拆分为count份
int avg = totalMoney / count;
int mod = totalMoney % count; //剩下来的零头
//除不开的零头,放在最后一个红包中,把红包全部放到一个集合中
for (int i = 0; i < count - 1; i++) {
redList.add(avg);
}
//最后一个红包
int last = avg + mod;
redList.add(last);
return redList;
}
}
class Member extends User{
public Member() {
}
public Member(String name, int money) {
super(name, money);
}
public void receive(ArrayList<Integer> list){
//从多个红包当中随便抽取一个给自己,随机获取一个集合中的索引编号
int index = new Random().nextInt(list.size());
//根据索引,从集合中删除,并且得到被删除的红包给自己
int data = list.remove(index);
//当前成员本来有多少钱
int money = super.getMoney();
//重新设置成员的钱
super.setMoney(money + data);
}
}
运行结果:
多态
访问成员变量的两种方式:
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找
在多态的代码当中,成员方法的访问规则是:
- 看new的是谁,就优先用谁,没有则向上找
Fu obj = new Zi(); //多态
对象的向上转型
| 格式 | |
|---|---|
| 父类名称 对象名 = new 子类名称(); | Animal animal = new Cat(); |
| 含义:右侧创建一个子类对象,把它当作父类来看待 | 创建了一只猫,当作动物看待,没问题 |
注意事项:向上转型一定是安全的。从小范围转向了大范围,从小范围的猫,向上转换成为了更大范围的动物
对象的向下转型
其实就是一个【还原】的动作
| 格式 | |
|---|---|
| 子类名称 对象名 = (子类名称)父类对象 | Cat cat = (Cat)animal; |
| 含义:将父类对象,【还原成为本来的子类对象】 | 本来是猫,已经被当作动物了,还原回来成为本来的猫 |
注意事项:
- 必须保证对象本来创建的时候就是猫,才能向下转型为猫
- 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错。
例子:
public class DuoTaiDemo {
public static void main(String[] args) {
//对象的向上转型,父类引用指向子类对象
AnimalClass animal = new CatClass();
animal.eat(); //猫吃鱼
/*对象一旦向上转型为父类,那么就无法调用子类原本特有的方法
animal.catchMouse(); //错误写法
解决方案:用对象的向下转型[还原]
* */
//向下转型,进行还原动作
CatClass cat = (CatClass) animal;
cat.catchMouse();
}
}
abstract class AnimalClass {
public abstract void eat();
}
class CatClass extends AnimalClass {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//子类特有方法
public void catchMouse(){
System.out.println("猫抓老鼠了!");
}
}
USB接口案例
笔记本电脑
案例分析
USB接口
public interface USBInterface {
public abstract void open(); //打开设备
public abstract void close(); //关闭设备
}
类
public class UsbDemo {
public static void main(String[] args) {
//首先创建一个笔记本电脑
Computer computer = new Computer();
computer.powerOn();
//准备一个鼠标
// Mouse mouse = new Mouse();
//首先进行向上转型
USBInterface usbMouse = new Mouse();
//参数是USB类型
computer.useDevice(usbMouse);
//创建一个USB键盘
Keyboard keyboard = new Keyboard(); //没有使用多态写法
computer.useDevice(keyboard);
computer.powerOff();
}
}
//鼠标就是一个USB设备
class Mouse implements USBInterface {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
}
//键盘是一个USB设备
class Keyboard implements USBInterface {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
}
class Computer{
public void powerOn() {
System.out.println("笔记本电脑开机");
}
public void powerOff() {
System.out.println("笔记本电脑关机");
}
//使用USB设备的方法,使用接口作为方法的参数
public void useDevice(USBInterface usb){
usb.open(); //打开设备
usb.close();//关闭设备
}
}
运行结果:
构造方法
构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式:
public 类名称(参数类型 参数名称){
方法体
}
注意事项:
- 构造方法的名称必须和所在类名称完全一样,就连大小写也要一样
- 构造方法不用写返回值类型,连void都不写
- 构造方法不能return一个具体的返回值
- 如果没有编写任何构造方法,那么编译器会默认赠送一个构造方法,没有参数、方法体什么都不做
- 一旦编写了一个构造方法,那么编译器不再赠送了。
public class Testday1 {
//名称Testday1 相同
public Testday1(){
System.out.println("构造方法执行了");
}
}
Scanner类
Scanner类的功能:可以实现键盘输入数据到程序当中
引用类型一般使用步骤:
1.导包
import 包路径.类名称
只有java.lang包下的内容不需要导包,其他包都需要import语句
2.创建
类名称 对象名 = new 类名称();
3.使用
对象名.成员方法名()
例子:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
//System.in代表从键盘输入
Scanner scanner = new Scanner(System.in);
//获取键盘输入的int数字
int num = scanner.nextInt();
System.out.println("输入的数字是:"+num);
//获取键盘输入字符串
String str = scanner.next();
System.out.println("输入的字符串是:"+str);
}
}
Random类
Random类用来生成随机数字
- 获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt()
- 获取一个随机的int数字(参数代表了范围,左闭右开取键):int num = r.nextInt(3)
实际上代表的含义是:[0,3) 也就是0~2
ArrayList类
数组的长度不可以改变,但是ArrayList集合的长度可以随意改变。
对于ArrayList来说,有一个尖括号代表泛型。
泛型:也就是装在集合当中所有的元素,全部是统一类型的。
注意:
- 泛型只能是引用类型,不能是基本类型。
- 对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。如果内容是空,得到的是空的忠括号:[]
例子:
import java.util.ArrayList;
public class ArrayListdemo {
public static void main(String[] args) {
//创建了一个ArrayList集合,集合里面装的全部是string字符串类型的数据
//备注:从JDK1.7开始,右侧的括号内部可以不写内容,但<>本身还是要写的
ArrayList<String> list = new ArrayList<>();
System.out.println(list); //[]
//向集合当中添加一些数据,需要用到add方法
list.add("天气真好");
list.add("雷雨天");
System.out.println(list);
}
}
如果希望向集合ArrayList忠存储基本数据类型,必须使用基本类型对应的“包装类”。
| 基本类型 | 包装类(引用类型,包装类都位于java.lang包下) |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
对象之间比较
==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法。
public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。
备注:任何对象都能用Object进行接收
public class EqualDemo {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
char[] charArray = {'h','e','l','l','o'};
String str3 = new String(charArray);
System.out.println(str1==str2); //true
System.out.println(str1==str3); //false
System.out.println(str2==str3); //false
System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str3)); //true
System.out.println(str2.equals(str3)); //true
}
}
静态static关键字
如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类。多个对象共享同一份数据。
public class StaticDemo {
public static void main(String[] args) {
Student one = new Student("张三",18);
one.room = "101教室"; //one的教室和two的教室因为static关键字所以共通
Student two = new Student("李四",20);
System.out.println("姓名:" + one.getName() + ",年龄:" + one.getAge() + ",教室:" + one.room);
System.out.println("姓名:" + two.getName() + ",年龄:" + two.getAge() + ",教室:" + two.room);
}
}
class Student {
private String name; //姓名
private int age; //年龄
static String room; //所在教室
public Student(){
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
}
一旦使用使用static修饰成员方法,那么这就成为了静态方法。
静态方法不属于对象,而是属于类的。
如果没有static关键字,那么必须先创建对象,然后通过对象使用成员方法。
对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名来调用。 对于本类当中的静态方法,可以省略类名称。
注意事项:
- 静态方法只能直接访问静态变量,成员方法可以直接访问成员变量和静态变量
原因:因为在内存中现有静态内容,后有非静态内容 - 静态方法当中不能使用this
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象 - 根据类名称访问静态成员变量的时候,就和对象没有关系了,只和类有关系。
静态代码块
格式:
public class 类名称{
static {
//静态代码块内容
}
}
特点:当第一次用到本类时,静态代码块执行唯一的一次。
静态的内容总是优先于非静态,所以静态代码块比构造方法先执行。
静态代码块典型用途:用来一次性地对静态成员变量进行赋值。
Arrays类
java.util.Arrays是一个与数组相关的工具类,里面提供了大量的静态方法,用来实现数组常见的操作。
public static String toString(数组):将参数数组变成字符串(按照默认格式:【元素1,元素2…】)
public class ArraysDemo {
public static void main(String[] args) {
int[] intArray = {10,20,30};
//将int数组按照默认格式变成字符串
String intStr = Arrays.toString(intArray);
System.out.println(intStr);
System.out.println(intStr instanceof String);
}
}
抽象abstract
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
//抽象类:抽象方法所在的类必须是抽象类才行。在class前写上abstract即可
abstract class Animal{
//这是一个抽象方法,代表吃东西,但是具体吃什么不确定
public abstract void eat();
}
如何使用抽象类和抽象方法
- 不能直接创建new抽象类对象
- 必须使用一个子类来继承抽象父类
- 子类必须覆盖重写抽象父类当中的所有抽象方法
覆盖重写:子类去掉抽象方法的abstract关键字,然后补上方法体大括号。 - 创建子类对象进行使用
public class Animalabstract {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
}
}
//抽象类:抽象方法所在的类必须是抽象类才行。在class前写上abstract即可
abstract class Animal{
//这是一个抽象方法,代表吃东西,但是具体吃什么不确定
public abstract void eat();
}
class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
接口
接口就是一种公共的规范标准。只要符合规范标准,就可以大家通用。
接口是一种引用数据类型,最重要的就是抽象方法。
如何定义一个接口的格式:
public interface 接口名称 {
// 接口内容
}
接口当中可以包含的内容:
- 常量
- 抽象方法
- 默认方法
- 静态方法
- 私有方法
/*在任何版本的Java中,接口都能定义抽象方法
格式:
public abstrace 返回值类型 方法名称(参数列表)
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性的省略
3.方法的三要素可以随意定义
* */
public interface MyInterface {
//抽象方法
public abstract void method1();
}
接口使用步骤
- 接口不能直接使用,必须有一个“实现类”来实现接口
格式:
public class 实现类名称 implements 接口名称{ ... }
- 接口的实现类必须覆盖重写接口中的所有抽象方法
实现:去掉abstract关键字,加上方法体大括号 - 创建实现类的对象,进行使用
例子:
public class InterfaceDemo {
public static void main(String[] args) {
/*错误写法,不能直接new接口对象使用
MyInterface inter = new MyInterface();
* */
//创建实现类的对象使用
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.method1();
impl.method2();
}
}
//使用alt + enter能够快捷产生覆盖MyInterface接口的重写方法
class MyInterfaceImpl implements MyInterface {
@Override
public void method1() {
System.out.println("方法1");
}
@Override
public void method2() {
System.out.println("方法2");
}
}
接口
public interface MyInterface {
//抽象方法
public abstract void method1();
public void method2();
}
运行结果:
接口中定义默认方法
格式:
public default 返回值类型 方法名称(参数列表){
方法体
}
备注:接口当中的默认方法能够解决接口升级的问题。
public interface MyInterface {
//抽象方法
public abstract void method1();
public void method2();
//新添加方法改为默认方法,不需要实现类重写
public default void methods3(){
System.out.println("新添加的默认方法");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
/*错误写法,不能直接new接口对象使用
MyInterface inter = new MyInterface();
* */
//创建实现类的对象使用
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.method1();
impl.method2();
//调用默认方法,如果实现类中没有,会向上找接口
impl.methods3();
}
}
接口中的私有方法
我们需要抽取一个公共方法,用来解决两个默认方法之间的重复代码问题。但是这个方法不应该让实现类使用,应该是私有化的。
私有方法只有接口自己能够调用。
- 普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) {
}
- 静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表) {
}
例子:
public interface MyInterface {
//新添加方法改为默认方法,不需要实现类重写
public default void methods3(){
System.out.println("新添加的默认方法3");
say();
}
public default void methods4(){
System.out.println("新添加的默认方法4");
say();
}
//私有方法
private void say(){
System.out.println("aaa");
System.out.println("bbb");
System.out.println("ccc");
}
}
接口中的常量
接口当中也可以定义成员变量,但是必须使用public static final三个关键字进行修饰。
从效果上看,这就是接口的【常量】
格式:
public static final 数据类型 常量名称 = "数据值";
一旦使用final关键字,就代表不可改变
接口当中的常量一定要进行明确的赋值
使用接口注意事项
- 接口是没有静态代码块或者构造方法的
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
class MyInterfaceImpl implements MyInterface,MyInterface2,MyInterface3
{
}
- 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
- 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖。
- 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
一起学习,一起进步 -.- ,如有错误,可以发评论