java基础语法
intelliJIDEA配置设置+快捷键
常用快捷键
mian方法:main或者psvm+回车
输出语句:sout+回车
ctrl+d:复制数据到下一行
ctrl+x:剪切数据,可以用来删除所在行
ctrl+alt+l:格式化代码
ctrl+/:对选中的代码添加单行注释
ctrl+shift+/:对选中的代码添加多行注释
数据类型
java中的关键字
标识符命名规则
组成规则
数字、字母、下划线和$组成
注意事项⚠️
不能以数字开头
不能是关键字
区分大小写
命名约定
方法、变量:小驼峰命名法(第一个单词首字母小写)
类:大驼峰命名法(第一个单子首字母大写)
算数运算符
数字相加
隐式转换
把一个表示数据范围小的数字或者变量赋值给另一个数据范围大的变量
方法
定义格式:
修饰符 返回值类型 方法名称(参数类型 参数名称,…){
方法体
return 返回值;
}
调用格式:
- 单独调用: 方法名称(参数);
- 打印调用: System.out.println(方法名称(参数));
- 赋值调用:数据类型 变量名称=方法名称(参数)
注意事项⚠️:
- 方法定义的先后顺序无所谓
- 方法定义必须是挨着的,不能在一个方法的内部定义另一个方法,必须定义在类中
- 方法定义之后不会自动执行,必须要调用执行
- 返回值类型固定写为void,这种方法只能单独调用,不能打印调用或赋值调用;不用写return
- 一个方法中可以有多个return语句,但是必须保证同时只有一个会被执行到;两个return不能连写
参数:
进入方法的数据
参数如果有多个,逗号分隔
返回值:
从方法中出来的数据
return 停止当前方法;将结果数据的返回值还给调用方。 return返回的返回值必须和方法名称前面的返回值类型保持一致
练习:
定义一个2个int数字相加的方法:
public static int sum(int a,int b){
int result=a+b;
return result;
}
public static void main(String[] args){
sum(10,20);//单独调用
System.out.println(sum(10,20));//打印调用
int number=sum(10,20);//赋值调用
System.out.println(number);
}
-------------------------------------------------------------------------
定义一个方法,用来判断两个数字是否相同
public static boolean isSame(int a,int b){
方法一:boolean same;
if(a==b){
same=true;
}else{
same=false;
}
-----------------------------------------------
方法二:boolean same=a==b?true:false;
------------------------------------------------
方法三:boolean same=a==b;
return same;
-------------------------------------------------
方法四:return a==b;
}
-------------------------------------------------------------------------
定义一个方法,用来求出1-100的所有数字之和
public static int sum(){
int result=0;
for(int i=1;i<=100;i++){
result+=i;
}
return sum;
}
-------------------------------------------------------------------------
定义一个方法,用来打印制定次数的helloworld
public static void printHello(int a){
for(int i=1;i<=a;i++){
System.out.println(“hello world”+i);
}
}
方法重载overload
方法重载:方法的名称一样,但是参数列表不一样
好处:只要记住唯一的方法名称,就能实现类似的多个功能
方法重载与下列因素有关:
- 参数个数不同
- 参数类型不同
- 参数的多类型顺序不同
方法重载与下列因素无关:
- 与参数的名称无关
- 与方法的返回值类型无关
练习:
比较两个数据是否相等
参数类型分别为byte类型,两个short类型,两个int类型,两个long类型
public static boolean isSame(byte a,byte b){
boolean same;
if(a==b){
same=true;
}else{
same=false;
}
return same;
}
public static boolean isSame(short a,short b){
boolean same=a==b?true:false;
return same;
}
public static boolean isSame(int a,int b){
return a==b;
}
public static boolean isSame(long a,long b){
if(a==b){
return true;
}else{
return false;
}
}
数组
数组的特点
- 数组是一种引用数据类型
- 数组当中的多个数据,类型必须统一
- 数组的长度在程序运行期间不可改变
数组的初始化
两种常见的初始化方式:
- 动态初始化(指定长度)
格式:
数据类型[] 数组名称=new 数据类型[数组长度]
- 静态初始化(指定内容)
格式:
标准格式:
数据类型[] 数组名称=new 数据类型[]{元素1,元素2,...}
省略格式:
数据类型[] 数组名称={元素1,元素2,...}
注意事项⚠️
- 静态初始化没有直接指定长度,但是依然会自动推算得到长度
- 静态初始化标准格式可以拆分成两个步骤
int[] arrayb;
arrayb=new int[]{1,2,3};
- 静态省略格式不能拆成两个步骤
- 动态初始化也可以拆分成2个步骤
int[] arrayb;
arrayb=new int[5];
- 使用动态输出化数组的时候,其中的元素将会拥有一个默认值
整数类型,默认值为0
浮点类型,默认值为0.0
字符类型,默认值为“\u0000”
布尔类型,默认值为false
引用类型,默认值为null
遍历数组
快捷方式:array.fori回车
for(int i=0;i<array.length;i++){
System.out.println(array[i]);
}
---------------------------------------------------------
练习:求出数组中的最大值
int[] array={5,8,3,4,6,8,9,80}
int max=array[0]
for(int i=1;i<array.length;i++){
if(max<array[i]){
max=array[i];
}
}
---------------------------------------------------------------
练习:反转数组
int[] array={5,8,3,4,6,8,9,80}
for(int min=0,int max=array.length-1;min<max;min++,max--){
int temp=array[min];
array[min]=array[max];
array[max]=temp;
}
java内存划分
-
栈stack:存放的都是方法中的局部变量
局部变量:方法的参数,方法{]内部的变量
作用域:一旦超出作用域,立即从栈内存中消失 -
堆heap:凡是new出来的东西,都在堆当中
堆内存里面的东西都有一个地址值:16进制
堆内存里面的数据,都有默认值
整数类型,默认值为0
浮点类型,默认值为0.0
字符类型,默认值为“\u0000”
布尔类型,默认值为false
引用类型,默认值为null
3.方法区method area:存储.class相关信息,包含方法的信息,静态区域:存放静态内容;非静态区域:存放非静态内容
3. 本地方法栈native method stack:与操作系统相关
4. 寄存器pc register:与cpu相关
面向对象
面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为
面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已具有该功能的人帮忙
类
类:是一组相关属性和行为的集合
属性:该书屋的状态信息
行为:该事物能做什么
对象
对象:是一类食物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为
类和对象的关系
类是对一类事物的描述,是抽象的
对象是一类事物的实例,是具体的
类是对象的模版,对象是类的实体
创建对象
类名称 对象名=new 类名称();
使用对象访问类中的成员:
对象名.成员变量;
对象名.成员方法();
public class Phone { // 成员变量
String brand; //品牌
int price; //价格
String color; //颜色
// 成员方法
//打电话
public void call(String name) {
System.out.println("给"+name+"打电话");
}
//发短信
public void sendMessage() {
System.out.println("群发短信"); }
}
public class Test02Phone {
public static void main(String[] args) {
//创建对象
Phone p = new Phone();
//输出成员变量值
System.out.println("品牌:"+p.brand);//null
System.out.println("价格:"+p.price);//0
System.out.println("颜色:"+p.color);//null
//给成员变量赋值
p.brand = "锤子";
p.price = 2999;
p.color = "棕色";
//再次输出成员变量值
System.out.println("品牌:"+p.brand);//锤子
System.out.println("价格:"+p.price);//2999
System.out.println("颜色:"+p.color);//棕色
//调用成员方法
p.call("紫霞");
p.sendMessage(); } }
成员变量和局部变量的区别:
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 类中方法外 | 方法内或者方法声明上 |
内存中位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕而消失 |
初始化值不同 | 有默认值 | 没有默认值,必须先定义,赋值,最后使用 |
private关键字
权限修饰符,可以修饰成员变量和成员方法,保护成员不被别的类使用
private修饰成员变量,提供2个相应的操作
- get变量名()方法, 用于获取成员变量的值,方法用public修饰
- set变量名(参数)方法,用于设置成员变量的值,方法用public修饰
封装
面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的 方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
封装步骤
- 使用private关键字来修饰成员变量
- 对需要访问的成员变量,提供对应的一对get、set方法
封装优化1- this关键字
this代表所在类当前对象的引用(地址值),即对象自己的引用
记住:方法被那个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
封装优化2- 构造方法
构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。
修饰符 构造方法名(参数列表){
// 方法体
}
注意事项⚠️:
- 如果你不提供构造方法,系统给默认给出无参构造方法
- 如果你提供了构造方法,系统将不再提供无参构造方法
- 构造方法是可以重载的,即可以定义参数,也可以不定义参数
标准的JavaBean
- 所有的成员变量都要使用private关键字修饰
- 为每一个成员变量编写一对getter/setter方法
- 编写一个无参数的构造方法
- 编写一个全参数的构造方法
GUI概述
JFrame
是一个顶层窗口
构造方法
JFrame():构造一个最初不可见的新窗体
成员方法
void setVisible(boolean b):显示或隐藏窗体具体取决于参数b的值
void setSize(int width,int height):调整此组件的大小,单位是像素
void setTitle(String title):设置窗体标题
void setLocationRelativeTo(null):设置窗体位置在中央弹出
void setDefaultCloseOperation(3):设置窗体关闭停止程序
void setAlwaysOnTop(true):设置窗体置顶
JButton
按钮的实现
构造方法
JButton(String text):创建一个带文本的按钮
成员方法
void setSize(int width,int height):设置大小
void setLocation(int x,int y):设置位置(x坐标,y坐标)
void setBounds(int x,int y,int width,int height):设置位置和大小
和窗体相关操作
取消窗体默认布局:窗体对象.setLayout(null)
把按钮添加到窗体:窗体对象.add(按钮对象)
JLabel
短文本字符串或图像的显示区域
构造方法
JLabel(String text):使用指定的文本创建 JLabel实例
JLabel(Icon image):使用指定的图像创建 JLabel实例
成员方法
void setBounds(int x,int y,int width,int height)
JTextArea文本域对象
构造方法
JTextArea()
成员方法
void setBounds(int x,int y,int width,int height)
JTextField文本对象
构造方法
JTextField()
成员方法
void setBounds(int x,int y,int width,int height)
Scanner类
实现键盘输入数据,到程序当中
//1. 导包
import java.util.Scanner;
public class Demo01_Scanner {
public static void main(String[] args) {
//2. 创建键盘录入数据的对象
Scanner sc = new Scanner(System.in);
//3. 接收数据
System.out.println("请录入一个整数:");
int i = sc.nextInt();
//4. 输出数据
System.out.println("i:"+i);
}
}
Date类
- 构造方法
Date():分配Date对象并对其进行初始化,使其表示分配时间,测量Date到毫秒
Date(long date):分配Date对象并初始化它以表示自标准基准事件以来的制定毫秒数
SimpleDateFormat是一个用于以区域设置敏感的方式格式化和解析日期的具体类
- 构造方法
SimpleDateFormat():构建一个SimpleDateFormat,使用默认模式和日期格式
SimpleDateFormat(String pattern):构造一个SimpleDateFormat使用给定的模式和默认的日期格式
格式化(从Date到String)
String format(Date date):将日期格式化成日期/时间字符串
解析(从String到Date)
Date parse(String source):从给定字符串开始解析文本以生成日期
匿名对象
没有变量名的对象
匿名对象使用场景:只能使用一次
- 匿名对象直接调用成员方法
- 匿名对象直接当作方法参数传递
- 匿名对象直接当作返回值
格式:
new 类名(参数列表);
作为参数:
class Test {
public static void main(String[] args) {
// 普通方式
Scanner sc = new Scanner(System.in);
input(sc);
//匿名对象作为方法接收的参数
input(new Scanner(System.in));
}
public static void input(Scanner sc){
System.out.println(sc);
}
}
作为返回值:
class Test2 {
public static void main(String[] args) {
// 普通方式
Scanner sc = getScanner();
}
public static Scanner getScanner(){
//普通方式
//Scanner sc = new Scanner(System.in);
//return sc;
//匿名对象作为方法返回值
return new Scanner(System.in);
}
}
Random类
Random r = new Random();
int i = r.nextInt()
练习:
获取1-n之间的随机数,包含n
// 导包
import java.util.Random;
public class Test01Random {
public static void main(String[] args) {
int n = 50;
// 创建对象
Random r = new Random();
// 获取随机数
int number = r.nextInt(n) + 1;
// 输出随机数
System.out.println("number:" + number);
}
}
猜数字:
import java.util.Random;
public class Test02Random {
public static void main(String[] args) {
Random r=new Random()
int number=r.nextInt(100)+1;
while(true){
Scanner sc = new Scanner(System.in);
System.out.println("请输入你要猜的数字(1‐100):");
int guessNumber = sc.nextInt();
// 比较这两个数据(用if语句)
if (guessNumber > number) {
System.out.println("你猜的数据" + guessNumber + "大了");
}
else if (guessNumber < number) {
System.out.println("你猜的数据" + guessNumber + "小了"); }
else { System.out.println("恭喜你,猜中了"); break; }
}
}
}
ArrayList类
是大小可变的数组,存储在内的数据称为元素
,表示一种指定的数据类型,叫做泛型。定义ArrayList需要指定将存储为哪种引用类型
ArrayList<String> list = new ArrayList<String>()
jdk7以后,右侧尖括号可以省略
ArrayList<String> list = new ArrayList<>();
常用方法和遍历
- public boolean add(E e) :将指定的元素添加到此集合的尾部。
- public E remove(int index) :移除此集合中指定位置上的元素。返回被删除的元素。
- public E get(int index) :返回此集合中指定位置上的元素。返回获取的元素。
- public int size() :返回此集合中的元素数。遍历集合时,可以控制索引范围,防止越界。
public class Demo01ArrayListMethod {
public static void main(String[] args) {
//创建集合对象
ArrayList<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
//public E get(int index):返回指定索引处的元素
System.out.println("get:"+list.get(0));
System.out.println("get:"+list.get(1));
System.out.println("get:"+list.get(2));
//public int size():返回集合中的元素的个数
System.out.println("size:"+list.size());
//public E remove(int index):删除指定索引处的元素,返回被删除的元素
System.out.println("remove:"+list.remove(0));
//遍历输出
for(int i = 0; i < list.size(); i++){
System.out.println(list.get(i));
}
}
}
基本类型 | 基本类型包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
对象添加到集合
public class Test02ArrayList {
public static void main(String[] args) {
//创建集合对象
ArrayList<Student> list = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("赵丽颖",18);
Student s2 = new Student("唐嫣",20);
Student s3 = new Student("景甜",25);
Student s4 = new Student("柳岩",19);
//把学生对象作为元素添加到集合中
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
//遍历集合
for(int x = 0; x < list.size(); x++) {
Student s = list.get(x);
System.out.println(s.getName()+"‐‐‐"+s.getAge());
}
}
}
public class listdemo {
//练习
//定义以指定格式打印集合的方法(ArrayList类型作为参数),使用{}扩起集合,使用@分隔每个元素。格式参照 {元素 @元素@元素}。
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("sss");
list.add("assss");
list.add("pppp");
printlist(list);
}
public static void printlist(ArrayList<String> list) {
System.out.print("{");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (i != list.size() - 1) {
System.out.print(s+"@");
} else {
System.out.print(s+"}");
}
}
}
}
//定义获取所有偶数元素集合的方法(ArrayList类型作为返回值
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
Random random=new Random();
for (int i = 0; i < 20; i++) {
int r=random.nextInt(1000)+1;
list.add(r);
}
ArrayList<Integer> smallList=getNewArrayList(list);
System.out.println(smallList);
}
public static ArrayList<Integer> getNewArrayList(ArrayList<Integer> list){
ArrayList<Integer> small=new ArrayList<>();
for (int i = 0; i <list.size() ; i++) {
Integer number=list.get(i);
if(number%2==0){
small.add(number);
}
}
return small;
}
}
String类
常用方法
- public boolean equals (Object anObject) :将此字符串与指定对象进行比较。
- public String trim () :去除字符串首、尾的空格
- public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写。
- public int length () :返回此字符串的长度。
- public String concat (String str) :将指定的字符串连接到该字符串的末尾
- public char charAt (int index) :返回指定索引处的 char值。
- public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
- public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
- public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到 endIndex截取字符串。含beginIndex,不含endIndex
- public char[] toCharArray () :将此字符串转换为新的字符数组
- public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
- public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使 用replacement字符串替换。
- public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
public static void main(String[] args) {
String s="helloworld";
// char charAt(int index):获取指定索引处的字符
System.out.println(s.charAt(0));//h
System.out.println(s.charAt(1));//e
// int indexOf(String str):获取str在字符串对象中第一次出现的索引,没有返回‐1
System.out.println(s.indexOf("l"));//2
// String substring(int start):从start开始截取字符串到字符串结尾
System.out.println(s.substring(0));//helloworld
System.out.println(s.substring(5));//world
// String substring(int start,int end):从start到end截取字符串。含start,不含end
System.out.println(s.substring(0, s.length()));//helloworld
System.out.println(s.substring(3,8));//lowor
// char[] toCharArray():把字符串转换为字符数组
char[] ch=s.toCharArray();
for (int i = 0; i<ch.length; i++) {
System.out.print(ch[i]);
}
System.out.println("==================");
// byte[] getBytes ():把字符串转换为字节数组
byte[] bytes = s.getBytes();
for (int i = 0; i<bytes.length; i++) {
System.out.println(ch[i]);
}
System.out.println("==================");
String replace = s.replace("hello", "IT");//ITworld
System.out.println(replace);
String ss = "aa|bb|cc";
String[] strArray = ss.split("|"); //
for(int x = 0; x < strArray.length; x++) {
System.out.print(strArray[x]); }//aa|bb|cc
}
练习:
//定义一个方法,把数组{1,2,3}按照指定个格式拼接成一个字符串。格式参照如下:[word1#word2#word3]。
public class listdemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
String s = arrayToString(arr);
System.out.println("s:" + s);
}
public static String arrayToString(int[] arr) {
//创建字符串s
String s = new String("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
s = s.concat(arr[i] + "]");
} else {
s = s.concat(arr[i] + "#");
}
}
return s;
}
}
基本类型包装类
将基本数据类型封装成对象的好处是可以通过对象调用方法操作数据
Integer
-
构造方法
integer(int value):根据int值创建integer对象(过时)
integer(String s):根据String值创建integer对象(过时) -
成员方法
static integer valueOf(int i):返回表示制定的int值的integer实例
static integer valueOf(String s):返回一个保存指定值的integer对象String
Integer i1=Integer.valueOf(100);
Integer i1=Integer.valueOf("100");
int转换成String
- static String valueOf(int i):返回int参数的字符串表示形式(String中的方法)
String转换成int
- static int parseInt(String s):将字符串解析为int类型(Integer中的方法)
自动装箱和拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
//自动装箱:基本类型-->包装类
Integer i1=100;
//自动拆箱:包装类-->基本类型
int i=i1;
Static关键字
被static修饰的成员变量,一般叫做静态变量
被static修饰的成员方法,一般叫做静态方法
static修饰的特点
- 被所在类的所有对象共享
- 随着类的加载而加载,优先于对象存在
- 可以通过类名调用,也可以通过对象名调用
类变量
当static修饰成员变量,称为类变量
定义格式:
static 数据类型 变量名;
静态方法
当static修饰成员方法时,称为类方法;也称为静态方法
修饰符 static 返回值类型 方法名 (参数列表){
// 执行语句
}
注意事项⚠️
- 静态方法可以直接访问静态类变量和静态方法
- 静态方法不能直接访问普通成员变量或成员方法;反之,成员方法可以直接访问类变量或静态方法
- 静态方法中,不能使用this关键字
//方法类变量
类名.类变量名
//调用静态方法
类名.静态方法名(参数)
静态代码块
定义在成员位置,使用static’修饰的代码块{}
- 位置:类中方法外
- 执行:随着类的加载而执行切执行一次,优先于main方法 和构造方法的执行
格式:
public class ClassName{
static {
// 执行语句
}
}
Arrays关键字
方法
- public static String toString(int[] a) :返回指定数组内容的字符串表示形式。
public static void main(String[] args) {
// 定义int 数组
int[] arr = {2,34,35,4,657,8,69,9};
// 打印数组,输出地址值
System.out.println(arr); // [I@2ac1fdc4
// 数组内容转为字符串
String s = Arrays.toString(arr); // 打印字符串,输出内容
System.out.println(s); // [2, 34, 35, 4, 657, 8, 69, 9] }
System.out.println(s instanceof String);//true
- public static void sort(int[] a) :对指定的 int 型数组按数字升序进行排序。
public static void main(String[] args) {
// 定义int 数组
int[] arr = {24, 7, 5, 48, 4, 46, 35, 11, 6, 2};
System.out.println("排序前:"+ Arrays.toString(arr)); // 排序前:[24, 7, 5, 48, 4, 46, 35, 11, 6, 2]
// 升序排序
Arrays.sort(arr);
System.out.println("排序后:"+ Arrays.toString(arr));// 排序后:[2, 4, 5, 6, 7, 11, 24, 35, 46, 48] }
练习:将一个随机字符串中的所有字符升序排列,并倒序打印
public static void main(String[] args) {
// 定义int 数组
String s="sdssfdasdfzvcxasharr";
char[] chars=s.toCharArray();
Arrays.sort(chars);
System.out.println(chars);
for (int i =chars.length-1; i >=0 ; i--) {
System.out.print(chars[i]);
}
}
Math类
方法
- public static double abs(double a) :返回 double 值的绝对值。
double d1 = Math.abs(‐5); //d1的值为5
double d2 = Math.abs(5); //d2的值为5
- public static double ceil(double a) :返回大于等于参数的最小的整数。
double d1 = Math.ceil(3.3); //d1的值为 4.0
double d2 = Math.ceil(‐3.3); //d2的值为 ‐3.0
double d3 = Math.ceil(5.1); //d3的值为 6.0
- public static double floor(double a) :返回小于等于参数最大的整数
double d1 = Math.floor(3.3); //d1的值为3.0
double d2 = Math.floor(‐3.3); //d2的值为‐4.0
double d3 = Math.floor(5.1); //d3的值为 5.0
- public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)
long d1 = Math.round(5.5); //d1的值为6.0
long d2 = Math.round(5.4); //d2的值为5.0
继承
就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接 访问父类中的非私有的属性和行为。
格式:
class 父类 { ... }
class 子类 extends 父类 { ... }
继承后的特点
- 如果子类父类出现不重名的成员变量,这时访问没有影响
class Fu {
// Fu中的成员变量。
int num = 5;
}
class Zi extends Fu {
// Zi中的成员变量
int num2 = 6;
// Zi中的成员方法
public void show() {
// 访问父类中的num
System.out.println("Fu num="+num);
// 继承而来,所以直接访问。
// 访问子类中的num2
System.out.println("Zi num2="+num2);
}
}
class ExtendDemo02 {
public static void main(String[] args) { /
/ 创建子类对象 Zi z = new Zi();
// 调用子类中的show方法
z.show();
}
}
演示结果: Fu num = 5 Zi num2 = 6
- 子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。
格式:
super.父类成员变量名
class Zi extends Fu {
// Zi中的成员变量
int num = 6;
public void show() {
//访问父类中的num
System.out.println("Fu num=" + super.num);
//访问子类中的num
System.out.println("Zi num=" + this.num); }
-如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
class Fu{
public void show(){
System.out.println("Fu类中的show方法执行");
}
}
class Zi extends Fu{
public void show2(){
System.out.println("Zi类中的show2方法执行");
}
}
public class ExtendsDemo04{
public static void main(String[] args) {
Zi z = new Zi(); //子类中没有show方法,但是可以找到父类方法去执行
z.show();
z.show2();
}
}
- 如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现
class Fu {
public void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu {
//子类重写了父类的show方法
public void show() {
System.out.println("Zi show");
}
}
public class ExtendsDemo05{
public static void main(String[] args) {
Zi z = new Zi(); // 子类中有show方法,只执行重写后的show方法
z.show(); // Zi show
}
}
注意事项⚠️
- 子类方法覆盖父类方法,必须要保证权限大于父类权限
- 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样
继承的特点
- java只能单继承,不支持多继承
- java支持多层继承(继承体系)
- 子类和父类是一种相对的概念
this关键字
- 访问本类中的成员变量 this.成员变量名=数据值
- 访问本类中的成员方法 this.成员方法()
- 访问本类中的构造方法
public test(){
}
public test(int i){
this()
}
this和super关键字
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量[本类成员变量] | this.成员方法(…)[本类成员方法] | this(…)[本类构造器 |
super | super.成员变量[父类成员变量] | super.成员方法(…)[父类成员方法] | super(…)[父类构造器 |
构造方法总结
子类中所有的构造方法,默认都会通过super()访问父类中午参的构造方法
每一个子类构造方法的第一句默认语句都是:super()
this(…)super(…)必须放在构造方法的第一行有效语句,两者不能共存
抽象类
抽象方法:没有方法体的方法
抽象类:包含抽象方法的类
abstract使用格式
抽象方法
使用abstract关键字修饰方法,该方法就成了抽象方法;抽象方法只包含一个方法名,没有方法体
修饰符 abstract 返回值类型 方法名 (参数列表);
抽象类
如果一个类包含抽象方法,那么该类必须是抽象类
abstract class 类名字 { }
抽象的使用
继承抽象类的子类必须重写父类的所有抽象方法,否则子类也必须声明为抽象类
注意事项⚠️
- 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类
- 抽象类的子类,必须重写抽象父类中的所有抽象方法,否则,编译无法通过而报错,除非是该子类也是抽象类
设计模式
- 什么是设计模式?一种解决方法
- 设计模式解决什么问题?解决开发中的常见问题,为了可重用代码,让代码更容易被他人理解,保证代码可靠性,程序的重用性,简单来说就是一套良好的编码风格,通过众多开发人员,长时间测试,经验总结而来,不同的设计模式也有不同的好处
模板设计模式
- 模板:就是一个固定的格式,把抽象类整体看作一个模板,模板中不能决定的东西定义成抽象方法
接口
使用interface关键字,接口不是类,是另一种引用数据类型
引用数据类型:数组、类、接口
接口的使用,它不能创建对象,但是可以被实现(implements,类似被继承),一个实现接口的类(可以看作接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类
接口的特点:
1、接口
public interface 接口名称 {
// 抽象方法
// 默认方法
// 静态方法
// 私有方法
}
含有抽象方法
该方法供子类实现使用
public interface InterFaceName {
public abstract void method();
}
含有默认方法和静态方法
默认方法:default修饰,拥有方法体,不可省略;供子类调用或者子类重写
静态方法:使用static修饰,供接口直接调用
public interface InterFaceName {
public default void method() {
// 执行语句
}
public static void method2() {
// 执行语句
} }
含有私有方法和私有静态方法
供接口中的默认方法或者静态方法调用
public interface InterFaceName {
private void method() {
// 执行语句
}
}
基本的实现
非抽象子类实现接口
- 必须重写接口中的所有抽象方法
- 继承了接口的默认方法,即可以直接调用,也可以重写
class 类名 implements 接口名 {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【可选】 }
抽象类重写
public interface LiveAble {
// 定义抽象方法
public abstract void eat();
public abstract void sleep(); }
//定义实现累
public class Animal implements LiveAble {
@Override
public void eat() {
System.out.println("吃东西"); }
@Override
public void sleep() {
System.out.println("晚上睡"); } }
//定义测试类
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用实现后的方法
a.eat();
a.sleep(); } }
默认方法的使用
public interface LiveAble {
public default void fly(){
System.out.println("天上飞"); } }
实现类:
public class Animal implements LiveAble {
// 继承,什么都不用写,直接调用 }
测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用默认方法
a.fly(); } }
重写默认方法
public class Animal implements LiveAble {
@Override
public void fly() {
System.out.println("自由自在的飞"); } }
静态方法的使用
public interface LiveAble {
public static void run(){
System.out.println("跑起来~~~"); } }
定义实现类:
public class Animal implements LiveAble {
// 无法重写静态方法 }
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
//Animal.run(); // 【错误】无法继承方法,也无法调用
LiveAble.run(); //跑起来~~~ } }
私有方法的使用
- 私有方法:只有默认方法可以调用
- 私有静态方法:默认方法和静态方法可以调用
接口的多实现
class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【不重名时可选】 }
- 接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
interface A {
public abstract void showA();
public abstract void show(); }
interface B {
public abstract void showB();
public abstract void show(); }
实现类:
public class C implements A,B{
@Override
public void showA() {
System.out.println("showA"); }
@Override
public void showB() {
System.out.println("showB"); }
@Override
public void show() {
System.out.println("show"); }
}
- 默认方法:接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。
interface A {
public default void showA();
public default void show(); }
interface B {
public default void showB();
public default void show(); }
实现类:
public class C implements A,B{
@Override
public void show() {
System.out.println("showtime"); }
- 静态方法:接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
- 优先级问题:当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执 行父类的成员方法。
interface A {
public default void methodA(){
System.out.println("AAAAAAAAAAAA"); } }
class D {
public void methodA(){
System.out.println("DDDDDDDDDDDD"); } }
class C extends D implements A {
// 未重写methodA方法 }
public class Test {
public static void main(String[] args) {
C c = new C();
c.methodA();//DDDDDDDDDDDD
}
}
注意事项⚠️
使用继承和接口的向上转型的时候,要注意:
选择好要声明的类型,否则会隐藏掉需要使用的部分
例如:
继承向上转型时,不能使用其他接口的方法,因为这些方法是子类实现的方法;
接口向上转型的时候,就不能继承父类的方法,同时也不再拥有其他接口的方法
多态
多态在使用时的细节:
1、多态时:父类和子类拥有一模一样的成员变量时:
编译时:以父类型中的成员变量为主
运行时:使用父类中的成员变量
父类和子类拥有一模一样的成员方法时:
编译时:以父类中的成员方法为主,检查父类有没有这个成员方法,没有报错
运行时:以子类的成员方法为主(调用子类对象中重写后的成员方法)
2、多态代码的书写:
创建对象:
//父类型 父引用=new 子类()
Father f=new son();
作为参数:
public void method(Father f){
f.方法();
}
作为返回值:
public Animal getInstance(){
return new Cat();
}
前提
1.继承或者实现
2.方法的重写
3. 父类引用指向子类对象
父类类型 变量名=new 子类对象;
变量名.方法名()
//父类类型:指子类对象继承的父类类型,或实现的父接口类型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法。
引用类型转换
向上转型
多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的
向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的
子类类型 变量名 = (子类类型) 父类变量名; 如:Cat c =(Cat) a;
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watchHouse() {
System.out.println("看家");
}
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse } }
转型的异常
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】 } }
这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了 Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。
为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse } } }
练习
定义usb接口
interface USB {
void open();
void close();
}
public class mouse implements USB{
@Override
public void open() {
System.out.println("鼠标开启,红灯闪一闪");
}
@Override
public void close() {
System.out.println("鼠标关闭,红灯熄灭");
}
public void click(){
System.out.println("鼠标单击");
}
}
public class KeyBoard implements USB{
@Override
public void open() {
System.out.println("键盘开启,绿灯闪一闪");
}
@Override
public void close() {
System.out.println("键盘关闭,绿灯熄灭");
}
public void type(){
System.out.println("键盘打字");
}
}
public class laptop {
public void run() {
System.out.println("笔记本运行");
}
public void useUSB(USB usb) {
if (usb != null){
usb.open();
}
if(usb instanceof mouse) {
mouse m = (mouse) usb;
m.click();
}else if(usb instanceof KeyBoard){
KeyBoard kb = (KeyBoard)usb;
kb.type();
}
usb.close();
}
public void shutDown() {
System.out.println("笔记本关闭"); }
}
//测试类
public class test {
public static void main(String[] args) {
laptop lt = new laptop();
lt.run();
USB u = new mouse();
lt.useUSB(u);
USB kb = new KeyBoard();
lt.useUSB(kb);
lt.shutDown();
}
}
代码块
静态代码块
特点:随着类加载到内存,会执行一次(类加载到方法区初始化的时候会执行静态代码块)
作用:可以对静态数据进行初始化
public class Student{
static{
//把构造方法中的共性内容写在构造代码块中
}
}
构造代码块
特点:会在每一个构造方法执行前,执行一次
作用:如果每个构造方法有重复的逻辑时
public class Student{
{
//把构造方法中的共性内容写在构造代码块中
}
}
局部代码块
写在方法体中的代码块
特点:在方法执行时,才会调用
作用:可以限定变量的作用域
final关键字
当某个变量不允许修改数据值时,可以使用final修饰变量
当某个方法不允许被子类重写时,可以使用final修饰方法
当某个类不允许被继承时,可以使用final修饰类
final:不可改变,可以用于修饰类、方法和变量
- 类:被修饰的类,不能被继承
final class 类名 { }
- 方法:被修饰的方法,不能被重写
修饰符 final 返回值类型 方法名(参数列表){ /
/方法体
}
-
变量:被修饰的对象,不能被重新赋值
-
局部变量-基本类型:基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。
-
局部变量-引用类型:引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改
public class FinalDemo2 {
public static void main(String[] args) {
// 创建 User 对象
final User u = new User();
// 创建 另一个 User对象
u = new User(); // 报错,指向了新的对象,地址值改变。
// 调用setName方法
u.setName("张三"); // 可以修改
}
}
- 成员变量:
显示初始化
public class User {
final String USERNAME = "张三";
private int age; }
构造方法初始化
public class User {
final String USERNAME ;
private int age;
public User(String username, int age) {
this.USERNAME = username;
this.age = age;
}
}
⚠️被final修饰的常量名称,一般都有书写规范,所有字母大写
权限修饰符
内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类
成员内部类
定义在类中方法外的类
class 外部类 {
class 内部类{ }
}
访问特点
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接访问外部类成员
if (live) {
System.out.println("心脏在跳动");
} else {
System.out.println("心脏不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
public class InnerDemo {
public static void main(String[] args) {
// 创建外部类对象
Person p = new Person();
// 创建内部类对象
Heart heart = p.new Heart();
// 调用内部类方法
heart.jump(); //心脏在跳动
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
heart.jump();//心脏不跳了
}
}
匿名内部类【重点】
是内部类的简化写法。它的本质是一个带具体实现的父类或者父接口的匿名的子类对象
以接口为例子,当使用一个接口时:
- 定义子类
- 重写接口的方法
- 创建子类对象
- 调用重写后的方法
匿名内部类就是将上诉4步变成一步
前提
匿名内部类必须继承一个父类或实现一个父接口
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
--------------------------------------
public abstract class FlyAble{
public abstract void fly();
}
public class InnerDemo {
public static void main(String[] args) {
/*1.等号右边:是匿名内部类,定义并创建该接口的子类对象
2.等号左边:是多态赋值,接口类型引用指向子类对象 */
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
//调用 fly方法,执行重写后的方法
f.fly();
}
}
引用类型用法总结
class作为成员变量
class Weapon {
String name; // 武器名称 、
int hurt; // 伤害值 }
class Armour {
String name;// 装备名称
int protect;// 防御值 }
class Role {
int id; // 角色id
int blood; // 生命值
String name; // 角色名称
Weapon wp;
Armour ar;
public Weapon getWp() {
return wp;
}
public void setWeapon(Weapon wp) {
this.wp = wp;
}
public Armour getArmour() {
return ar;
}
public void setArmour(Armour ar) {
this.ar = ar;
}
// 攻击方法
public void attack(){
System.out.println("使用"+ wp.getName() +", 造成"+wp.getHurt()+"点伤害"); }
// 穿戴盔甲
public void wear(){
// 增加防御,就是增加blood值
this.blood += ar.getProtect();
System.out.println("穿上"+ar.getName()+", 生命值增加"+ar.getProtect());
}
}
public class Test {
public static void main(String[] args) {
// 创建Weapon 对象
Weapon wp = new Weapon("屠龙刀" , 999999);
Armour ar = new Armour("麒麟甲",10000);
Role r = new Role()
// 设置武器属性
r.setWeapon(wp);
r.setArmour(ar);
r.attack();
r.wear();
}
}
interface作为成员变量
// 法术攻击
public interface FaShuSkill {
public abstract void faShuAttack(); }
public class Role {
FaShuSkill fs;
public void setFaShuSkill(FaShuSkill fs) {
this.fs = fs; }
// 法术攻击
public void faShuSkillAttack(){
System.out.print("发动法术攻击:");
fs.faShuAttack();
System.out.println("攻击完毕");
}
}
public class Test {
public static void main(String[] args) {
Role role = new Role();
role.setFaShuSkill(new FaShuSkill() {
@Override
public void faShuAttack() {
System.out.println("纵横天下");
}
});
role.faShuSkillAttack();
}
}
interface作为方法参数和返回值类型
例如arrylist就是java.util.List 接口的实现类
耦合性
耦合性:类与类之间功能关系的联系紧密程度
当修改父类中没有被重写的方法的时候,可能会导致其他子类在使用中出现错误
接口可以降低耦合性,因为接口方法都是没有被实现的,只能实现类进行修改,不会影响更大的范围