数组:
引言:变量存储同一组数据的弊端:
1:命名和书写繁琐、2:使用的效率低下
引入数组概念:
数组:是内存中一块连续的存储空间、作用:是为了同时存放多个相同数据类型的值
创建【代码演示】
第一种方式:先声明,后指明长度
数据类型 [] 数组名;//声明
数组名=new 数据类型[长度];
//案例书写
int [] arr;
arr=new int[3];
后续补充:
数据类型 []数组名;、数据类型[]数组名;、数据类型 数组名[];
书写要求:
1:数组创建时,必须指明长度,作用为方便内存分配空间
2:长度必须为整形
第二种:声明的同时直接指明长度
数据类型[]数组名=new 数据类型[长度];
//代码演示:
int []arr2=new int[3];
第三种:创建的同时直接存放数据
数据类型 []数组名=new 数据类型[]{值1,值2,值n};
//案列书写:
int [] arr3=new int []{10,20,30,40};
补充:1:数组长度由值的个数决定
2:右侧[]中不可再次指明长度
第四种:创建的同时直接存放数据【简写】
数据类型[]数组名={值1,值2,值n};
//案列演示:
int[]arr4={10,20,30,40};
补充:无法先声明,后{}|直接赋值
正确错误对比:
int []arr5;
arr5={10,30,40}//错误
arr5=new int[]{10,20,30,40}//正确
使用说明:
1:通过下标操作数组元素、2:下标从0开始,至数组长度前一位结束、3:通过下标取值赋值
//取值:
数组名[下标];
//存值:
数组名[下标]=值
4:下标的使用不可超出范围,否则会爆出数组下标越界异常,
//报错代码:
java.lang.ArrayIndexOutBoundsException;
5:可以通过数组名.length动态获取数组长度
遍历
概念:依次获取查看数组的数据
for(int i=0;i<数组名.length;i++){
//i代表下标
//通过数组名[i]获取当前正在被遍历的数组值
}
数组进阶:
1:数组时引用类型,2:底层存放:栈中存放引用名(数组名)引用名对应堆中的一块空间,堆空间中存放数组的具体信息(值)3:引用类型之间相互赋值传递的是堆地址4:”逢new必开“:只要执行到new关键字,堆中一定会开辟空间5:为了博正内存空间的正常分配,数组存在默认值
备注:
默认值:是编译器给的,是空间的第一次赋值,初始值:是程序员手动第一次赋值,
默认值补充:
int 0、double 0.0、boolean:false、char:空、String :null
数组扩容:
1:创建一个长度更大的数组(通常为原数组的2倍)
2:将原数组的数据赋值到新数组中
3:将引用的地址转向新数组
第一种方式:利用for循环
public static void main(String[]args){
//原数组:整形数组
int a[]={10,20,30,40};
//需求:将数组a扩容2倍
//第一步:创建一个长度为a的两倍的数组
int [] newa=new int[a.length*2];
//第二步:将原数组数据赋值到新数组中
//遍历数组a
for(int i=0;i<a.length;i++){
//将当前元素的值赋值给新数组
newa[i]=a[i];
}
a=newa;
//查看原数组数据:
for (int i=0;i>a.length;i++){
System.out.println(a[i]);
}
}
第二种方式:利用arraycopy方法
System.attaycopy(原数组名,原数组复制起始下标,,新数组名,新数组存放其实下标,复制长度)
第三种方式:利用copyOf方法
新数组地址 java.util.Arrats.copyOf(原数组名,预期的数组长度)
数组缩容同理
数组排序
冒泡排序:
1:让相邻的两个位置进行比较,每轮比较结束之后都会确定一个值(从后往前)
2:实现思路:外层循环代表比较轮数,内层循环代表比较次数
int []a={12,32,45,65,78};
for(int i=1;i<a.length;i++){
for(int j=0;i<a.length-1;j++){
//让下一个元素和当前元素比较
//从小到大,小于号,从大到小,大于号
if(a[j+1]<a[j]){
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
]
]
选择排序
1:固定一个下标位置,让其它下标位置与其比较,根据比较结果决定是否换位
2:每轮比较结束后,固定下标位置的值将被确定
3:实现思路:外层循环遍历固定下标,内层循环遍历与其比较的下标
int[] a = {99, 55, 77, 1};
for (int i = 0; i < a.length - 1; i++) {//固定的下标范围
for (int j = i + 1; j < a.length; j++) {//比较的下标
//判断比较位置的值是否小于固定位置的值
//从小到大:小于号 从大到小:大于号
if (a[j] < a[i]) {
//值换位
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}
}
JDK排序
java.util.Arrays.sort(数组名):对数组元素进行快速的升序排列
int []a={22,34,54,64,12,23}
Arrays.sort(a);
面向对象基础:
引言:
面向过程:关注的是实现需求的步骤,面向对象:关注的是实现需求的方式
ps:面向对象底层包含面向过程
对象的理解:
对java来讲:”万物皆对象“
对象:指操作单位:任何内容都可以被认定为独立的操作单位,
对程序来讲:是计算机内存中的一块存储空间,用来存放现实生活中的对象内容
对象间的关系
第一种:is a :对象与对象间的继承
第二种:has a一个对象包含另一个对象
第三种:use a 一个对象使用另一个对象
类的补充:
类:是用来描述同一批具有相同特征和行为的对象
描述该批对象都具有那些共有特征和行为
约束相同对象应该具有那些特征和行为
测试类:拥有主函数,可以直接运行
描述型的类:描述对象,没有主函数,无法直接运行类
类和对象间的关系:
重点:1;类是对象的模板,2:对象是类的实例,
注意:一个模板可以拥有多个相同相似的实例
必须先存有模板,才能通过模板构建实例 类的组成:
包:com.xxx.entity
1:属性:用来描述特征,也称为全局变量,成员变量,成员属性等
特征:对象有什么
//只声明
数据类型 数据名;
//声明的同时赋初始值
数据类型 属性名=值
位置:类的内部,方法的外部,通常写在类的最上方
局部变量 | 属性 | |
位置 | 方法内部 | 方法外部 |
作用范围: | 从定义行开始,至直属代码块结束 | 整个类 |
命名冲突 | 同一作用范围内,不可重名 | 可以与局部变量重名,优先级更高 |
默认值: | 没有 | 有 |
方法:用来描述行为,也成为成员方法,实例方法等
函数是方法的一种,也称为静态方法,需要添加static修饰符
访问修饰符 返回值类型 方法名(形参列表){
// 操作语句
}
位置:类的内部,其他方法的外部,与属性平级
创建对象
类名 对象名 =new 类名()
测试类:com.xxx.test
对象访问
1:访问属性:
取值:对象名.属性名
赋值:对象名.属性名=值;
2:访问方法
对象名.方法名(实参)
构造方法
作用为创建对象,且对创建必须借助构造方法
无参构造:
访问修饰符 类名(){};
有参构造:
访问修饰符 类名(数据类型 参数名1,数据类型 参数名2,数据类型 参数名n){
属性名1=参数1;
属性名2=参数2;
属性名n=参数n;
}
语法特点:
1:没有返回值部分
2:方法名必须与类名保持一致
3:访问修饰符通常为public
使用特点:
1:创建对象语法解析
类名 对象名=new 类名()
左侧类名:声明创建的为哪个类的对象
右侧类名():调用构造方法
2:只能通过new关键字调用
3:语法补充:
利用有参构造创建对象:
类名 对象名=new 类名(实参列表);
4:无参与有参创建对象的区别:
无参构造只创建对象
有参构造在创建对象完成后可以为属性赋初始值
5:类中会默认存在一个无参构造,当类中手动定义构造后,默认存在的无参构造将会失效
6:无参构造可以存在0-1个,有参构造可以存在0-多个
7:根据实参列表决定执行的是那个构造
方法重载
引言:当面对多个功能相似或想同的方法时,方法名之间的定义繁琐以及调用时的匹配繁琐时需要解决的问题
作用:允许多个功能相同或相似的方法命名一致,简化程序员定义与调用时的负担
使用规则
1:在同一类种,方法名相同,参数列表不同
2:与访问修饰符,返回值类型,异常没有关系
this关键字
代表当前对象
this.
指明或调用本类的属性或方法
指明本类属性:this。属性名
调用本类方法:this.方法名(实参) 不常用
有参构造的标准语法结构:
public 类名(数据类型 属性名1,数据类型 属性名2,数据类型 属性名n){
this.属性名=属性名;
}
this()
调用本类其他构造的内容
使用
1:根据实参列表决定执行的是那个构造的内容
2:必须写在构造方法有效代码的第一行
3:无法递归调用
封装
引言:是一种屏障,作用为防止对象数据被外界任意访问和更改
步骤:
1:数据私有化
private 数类型 属性名;
含义 | 可作用范围 | |
public | 公共的,公开的 | 所有位置都可以访问 |
private | 私有的 | 本类内部可以访问 |
私有化之后的属性只有定义其的内部可以使用,其他类无法访问
可以选择性的对属性进行私有化操作,但是通常情况下,所有属性都应该参与私有化
2:提供取值(getter)、赋值(setter)的方法通道
getter:get+属性名(属性名首字母大写)
如果属性类型为布尔类型,is+属性名(首字母大写)
public 返回值类型 getXxx(){
return 属性名
}
有返回值,无参数
返回值类型与对应属性保持一致
setter:set+属性名(属性名首字母大写)
public void setXxx(数据类型 属性名){
this.属性名=属性名
}
无返回值,有参数
可以选择性的为私有化属性提供getter、setter方法,但是通常情况下,都需要具备
使用
属性封装之后,无法再通过对象名.属性名那个的方式访问属性,需要通过调用方法来实现
取值:对象名.getXxx()
赋值:对象名.setXxx(实参);
访问修饰符
控制内容可被访问的范围
本类 | 同包 | 非同包子类 | 非同包非子类 | |
private(私有的) | √ | |||
default(默认的) | √ | √ | ||
protected(受保护的) | √ | √ | √ | |
public(公开的) | √ | √ | √ | √ |
1:degault身为访问修饰符,无法显示声明
2:只有public和default可以修饰
3:四个访问修饰符都可以修饰属性、方法、构造
4:四个访问修饰符都无法修饰局部变量
对象的创建过程
又名属性的三个赋值时期
1:给属性开辟空间,赋默认值(必须执行
2:给属性赋初始值
3:执行构造内容时再次赋值
继承
实际开发中,类与类之间代码会出现冗余,处理方式:将重复代码提炼至第三个类,书写双方之间的继承关系
概念:
将子类的共性内容进行抽取,生成父类,建立在继承关系下,子类可以继承拥有父类所有可被继承的内容
语法
public Class 子类类名 extends 父类类名{
}
使用
1:必须建立在is a关系之上
2:子类可以拥有独有内容
3:父类无法访问子类独有内容
4:一个类在身为子类的同时仍可以是其他类的父类
5:子类可以继承拥有所有父类所有可被继承的内容
6:一个子类只能拥有一个直接父类
7:一个父类可以拥有多个直接子类
8:父类构造,子类无法继承
9:父类的私有内容,子类无法直接继承访问
方法重写(覆盖)
在继承关系下,如果子类不满足于父类提供的方法实现,则可以选择对方法实现进行重写
概念:
子类对父类中继承过来的方法进行方法题的重写书写,简称方法重写
规则;
1:方法名、参数列表、返回值类型必须与父类保持一致
2:访问修饰符必须与父类相同或者更宽
3:不允许抛出比父类更大或更多的异常
使用:
方法重写之后,子类对象会优先执行自身重写之后的内容
父类的作用:
解决子类之间的代码冗余问题
强制子类拥有某些内容
子类的内存结果
子类的内存空间由父类内容+独有内容构成
父类封装
父类也是类,所以内部属性也应该及逆行系统性的封装
父类将属性封装之后,子类无法直接通过对象名.属性名的方式直接访问父类声明属性,必须通过对象名.getter()、对象名.setter()的形式堆属性进行访问
super关键字
代表父类对象
super()
作用为调用父类构造内容
使用要求:
1:通过实参列表决定调用的是哪个父类构造
2:必须写在构造方法有效代码第一行
3:无法与this()共存
4:子类构造第一行默认存在无参的super(),当手动调用super方法之后或书写了this方法调节之后,该默认存在的super()将会失效
语法:可以借助super()实现子类有参构造中为父类中声明的属性赋值的操作
1. 父类中正常声明有参构造
public class Animal {
//特征:名字、年龄、性别
private String name;
private int age;
private String sex;
public Animal(){}
public Animal(String name,int age,String sex){
System.out.println("正在执行animal有参构造...");
this.name = name;
this.age = age;
this.sex = sex;
}
//getter、setter方法
...
//行为:吃饭、睡觉
...
}
2. 子类书写有参构造,将希望赋值的形参正常声明,内部调用super()利用对应的父类有参构造实现赋值
public class Dog extends Animal{
public Dog(){}
public Dog(String name,int age,String sex){
//调用父类中的有参构造方法为父类中声明的属性赋值
super(name,age,sex);
}
}
super.
指明调用父类属性或方法
super.属性名
super.方法名(实参)
父类属性封装之后,无法通过super.属性名访问父类属性
有继承关系的对象创造过程
1:给父|子类属性分配空间,赋默认值
2:给父类属性赋初始值
3:执行父类构造再次赋值
4:给子类属性赋初始值
5:执行子类构造再次赋值
先构造父类内容,再构造子类内容
多态
父类引用的多种具体值的不同形态
概念:
父类引用可以指向不同的子类对象
父类引用名=子类对象
父类类名 引用名=new 子类类名();
使用
1:实际创建的是子类对象
2:优先访问子类独有内容
3:无法访问子类独有内容!原因:编译不通过
4:编译器关注的是引用类型,解释器关注的是实际对象类型
ps:左边决定做什么,, 右边决定谁去做
引用类型间的类型转换
自动类型转换
父类引用=子类对象
强制类型转换
子类类型=(子类类型)父类引用
子类类名 引用名=(子类类名)父类引用名;
只能转向父类引用原本指向的子类类型
Animal a1 = new Dog();
Cat c = (Cat) a1;//错误! 运行报错
-
a1类型为Animal,满足语法规范,编译通过,但是a1的实际对象类型是Dog,不满足执行逻辑,所以运行报错
同极子类之间无法进行类型强转
多态的应用场景
多态的应用场景
用于容器:将容器(变量、数组、集合等)类型声明为大类型,则内部可以存放不同的小类型对象
2:用于参数:将方法形参类型声明为大类型,则传入实参时,可以为不同的子类对象
3:用于返回值:将方法返回值类型声明为大类型,则可以实际return不同的子类对象
接收返回时,也应该使用父类引用类型接收
instanceof关键字
==基本类型比较值,引用类型比较地址
判断引用是否于指定类型兼容
引用名 instaceof 类名
使用
1:子类对象可以被父类类型兼容
2:父类对象无法被子类类型兼容
3:同级子类之间无法兼容
大类型可以兼容小类型,但是小类型无法兼容大类型
多态的好处:
1:更加贴合显示逻辑
2:提高代码扩展性
3:减少代码冗余