活动地址:CSDN21天学习挑战赛
面向对象
1.类的构造方法
-
什么是类的构造方法 ----> 一个比较特殊的方法
- 方法名和类名相同
- 没有void
- 构造方法可以重载
-
分类
-
无参构造方法(构造器)
public 方法名(){ }
注意:
-
方法名与类名一致
-
没写构造方法是,系统默认为无参构造方法, 但是当如果提供有参构造方法时,系统就不会在提供无参构造方法
-
-
有参构造方法(构造器)
public 方法名(参数类型 参数名,...){ }
注意:
- 方法名与类名一致
-
-
构造方法的目的
- 为了类的成员相关的数据,进行初始化
- 系统默认初始化
- 显示初始化
- 为了类的成员相关的数据,进行初始化
-
一个标准类(JavaBean)的写法:
-
成员变量私有化
-
提供对外的公共访问方法,setXXX()/getXXX()
-
提供无参构造/ 有参构造方法 (根据需求进行判断)
-
/*学生有姓名,年龄,性别属性,行为有学习,睡觉以及玩游戏的行为,
睡觉的行为,没有返回值类型; 玩游戏的行为:有一个字符串String类型的参数 gameName
请使用面向对象方式书写学生类并且进行测试(使用标准类完成并进行测试)*/
public class Student {
String name;
int age;
String sex;
//无参构造方法
public Student() {
}
//有参构造方法
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void study(){
System.out.println(name + "正在学习中......");
}
public void sleep(){
System.out.println(name + "正在睡觉......");
}
//玩游戏的行为:有一个字符串String类型的参数 gameName
public void game(String gameName){
System.out.println(gameName + "正在玩游戏......");
}
}
//测试类
public class StudentTest {
public static void main(String[] args) {
//无参构造方法
Student student = new Student();
student.setName("天天");
student.setAge(25);
student.setSex("女");
System.out.println("姓名:" + student.getName() + "\n" + "年龄:" + student.getAge() + "\n" +"性别:" +
student.getSex());
student.study();
student.sleep();
student.game("DOTA");
System.out.println("---------------------------------------------");
//有参构造方法
Student student1 = new Student("向向",25,"男");
System.out.println("姓名:" + student1.getName() + "\n" + "年龄:" + student1.getAge() + "\n" +"性别:" +
student1.getSex());
student1.study();
student1.sleep();
student1.game("DOTA");
}
}
2.static关键字
- 特点
- 被静态修饰的,随着类的加载而加载,优先于对象存在
- 不能和this共存
- 本身含义就是共享,共用,可以多个对象共享共用
- 被静态修饰的成员变量或者成员方法,叫做静态变量或者静态方法
public class Person {
//属性:姓名,年龄和国籍,先不用私有
String name ; //姓名
int age ; //年龄
static String country ;// 国籍
//永远给出无参构造方法
public Person(){}
//给出有参构造方法 ---带两个参数
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
//带三个参的构造方法
public Person(String name,int age,String country){
this.name = name ;
this.age = age ;
this.country = country ;
}
//show方法,展示这个人具体信息
public void show(){
System.out.println("这个人姓名是:"+name+",年龄是:"+age+",所在的国籍是:"+country);
}
}
//测试类
public class PersonTest {
public static void main(String[] args) {
//测试
//描述 古代四大美女
Person p1 = new Person("貂蝉",25,"中国") ;
p1.show();
Person p2 = new Person("王昭君",21);
p2.show();
Person p3 = new Person("西施",22);
p3.show();
Person p4 = new Person("杨玉环",27); //只有第一个输入"中国",但后面3个同样输出"中国"
p4.show();
}
}
-
访问的方式:
-
可以使用对象名来访问,但是,对于系统来说(jvm)对静态的东西:变量/方法,都是通过类名直接访问 * 类名.变量名; * 类名.方法名();
-
-
静态的使用场景适用于范围:
-
简单记忆:静态只能用于访问静态 * 静态方法中只能访问静态变量 * 静态方法只能调用静态方法 * 非静态方法皆可以访问静态的东西也可以访问非静态的东西
-
public class ArrayTool {
//提供一个私有的构造方法,为了外界不能直接new
private ArrayTool(){}
public static void printArray(int[] arr){ //形式参数---引用类型,数组类型,需要传递这个数组的对象
System.out.print("[");
for(int x = 0 ; x <arr.length ; x ++){
//如果x角标取到最大索引值
if(x==arr.length-1){
System.out.println(arr[x]+"]");
}else{
System.out.print(arr[x]+", ");
}
}
}
}
//测试类
public class ArrayTest {
public static void main(String[] args) { //静态只能访问静态
//数组,静态初始化了
int[] arr = {65,13,24,97,78} ;
//新的访问:使用工具类名.静态方法名()
//遍历
ArrayTool.printArray(arr) ;
}
}
3.javadoc注释文档(补充)
- 对ArrayTool.java文件产生一个文档说明书 ----> 类似于API(Application Programming Interface:应用程序接口文档)
-
使用jdk安装目录里面的bin里面: javadoc.exe 指令,产生文档说书的指令
-
将ArrayTool这个java文件代码复制到本地某个磁盘上,类名和文件名称一致(先不要把package复制上去)
-
打开dos窗口,进入到这个java文件的路径下(保证访问权限足够大:public)
-
用javadoc -d 目录名称 -author -version ArrayTool.java(java源文件带后缀) 产生文档说明书
-
/**
*ArrayTool类是针对数组操作的工具类,里面包含了数组的遍历功能,求数组最值问题,
* 获取数组的元素第一次出现索引值,冒泡排序等提供很多功能;
* @author In-Deep
* @version V8.0
*/
public class ArrayTool {
private ArrayTool(){}
/**
* 这个方法是针对数组的遍历功能,将数组按照指定格式输出,输出格式如下:
* [元素1, 元素2, 元素3, 元素4,....元素n]
* @param arr 要传递的真实数组(要遍历的数组对象)
*/
public static void printArray(int[] arr){
System.out.print("[");
for(int x = 0; x <arr.length; x++){
//如果x角标取到最大索引值
if(x==arr.length-1){
System.out.println(arr[x]+"]");
}else{
System.out.print(arr[x]+", ");
}
}
}
/**
* 这个方法是获取数组中的最大值;
* @param arr 要传递数组对象,在这里面查询最大值
* @return 返回数组中的最大值
*/
public static int getMax(int[] arr){
int max = arr[0];
for(int x =1; x <arr.length; x++){
if(arr[x]>max){
max = arr[x];
}
}
return max;
}
/**
* 这个方法是获取数组中第一次出现索引值
* @param arr 要查询的数组
* @param key 要查找在数组中的指定的元素
* @return 返回的就是数组的元素第一次出现的索引值,否则,返回-1
*/
public static int getIndex(int[] arr,int key){
int index = -1;
for(int i = 0; i <arr.length; i++){
if(key == arr[i]){
index = i;
break;
}
}
return index;
}
/**
* 这个方法是对数组进行冒泡排序
* @param arr 要将数组进行排序
*/
public static void bubleSort(int[] arr){
for(int x = 0; x < arr.length -1; x++){
for(int y = 0; y < arr.length-1-x; y++){
if(arr[y] >arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
}
4.代码块
-
代码块 ----> 使用{}括起来的内容
-
分类:
-
局部代码块,就是在方法定义中使用{}
-
{},作用:就是限定局部变量的生命周期;
-
-
构造代码块:—在类的成员位置定义的{}
-
特点:在执行构造方法之前,如果类中有构造代码块,则优先执行构造代码块 * 作用:也可以给类的成员的数据进行初始化
-
只要执行构造方法,如果存在构代码块,它必须优先执行,然后才是构造方法...
-
-
静态代码块:
-
类就加载一次,静态代码块也就执行一次
-
格式 ----> 跟静态相关的都和类有关系,随着类的加载而加载
static{ //里面书写代码 }
-
-
优先级:
- 静态代码块 > 构造代码块> 构造方法,并且每次执行构造方法之前,优先执行所有的构造代码块
//测试类 public class CodeDemo { public static void main(String[] args) { //局部代码块 { int y = 20 ; System.out.println(y); } System.out.println("----------------------------------------------") ; Code code = new Code(); Code code1 = new Code("华为"); } } class Code{ { int x = 100; System.out.println(x); } //无参 public Code(){ System.out.println("code"); } { int y = 1000; System.out.println(y); } //静态代码块 static { int z = 10000; System.out.println(z); } //有参 public Code(String brand){ System.out.println("brand:" + brand); } }
-
5.继承
-
将多个类的共性内容抽取出来,放在一个独立的类中,让这个独立的类和其他类产生一种关系
- “继承” ----> 关键字 extends
-
格式
class 父类名{ 共性内容:姓名,年龄..... 提供公共的访问方法setXXX()/getXXX() } class 子类名 extends 父类名{ }
-
优点
-
可以提高代码复用性
-
可以提高代码的维护性,后期便于维护,针对子类和父类进行维护(子父关系明确)
-
类与类产生的继承关系,是"多态"的前提条件
-
在Java中有一个开发原则 "低耦合,高内聚"(Java设计模式都需要遵循这一个原则) * 耦合性:开发中是永远避免不了,可以降低(耦合:类和类的关系) * 内聚性:指的是某个类完成某个功能的一种能力; 尽量不要产生继承关系来完成一个功能,尽量一个类能完成一个类完成; * 低耦合:降低耦合性,减少类和类的关系;
-
-
特点
-
在Java语言中,类和的类的关系是一种继承关系,这个继承只能支持"单继承",不支持多继承
-
class 父{} class 父2{} class 子 extends 父,父2{} //多继承:不支持 错 class 子 extends 父{} //正常的语法格式 对
-
类和类关系,虽然不支持多继承,但是层层单继承----> 多层继承
//定义父类 class GrandFather{ public void method(){ System.out.println("我是爷爷"); } } //定义父类 class Father extends GrandFather{ public void show(){ System.out.println("我是父亲"); } } //父类 //class Mother{} //子类 //class Son extends Father,Mother{} //子类不能继承多个父类,多继承语法不支持 class Son extends Father{ //自己的特有功能 public void playGame(){ System.out.println("会玩游戏"); } } public class ExtendsDemo { public static void main(String[] args) { //创建Son类对象 Son s = new Son() ; s.show(); //访问父亲的方法 s.method();//访问爷爷的方法(method方法间接继承过来) s.playGame(); //访问自己的方法 }
-
注意:
子类继承父类,对于非私有的成员,直接可以继承过来,但是如果是私有成员,它可以通过公共的访问去访问,但不是直接访问的
被私有修饰的东西(成员变量/成员方法),只能在当前类访问的
-
在继承关系中,构造方法的访问问题(重点):
-
子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
-
为什么?
-
子类继承父类,会用到父类的数据,需要让父类先进行初始化; 一个类初始化的---肯定需要执行构造方法的
-
-
如果一个父类存在有参构造方法,没有无参构造方法,子类的所有构造会出现什么问题?出现了问题,怎么解决?
-
子类的所有全部构造方法报错,子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
-
解决方案1:
-
手动给出无参构造方法
public 类名(){ }
-
-
解决方案2:
-
假设,人家现在就不需要让你给出父类的无参构造方法,就需要让子类的构造方法,显示的访问父类的有参构造方法 * 要使用关键字 <strong>super</strong>:代表父类空间标识(代表的父类对象的地址值引用) * super() :访问父类的无参构造方法 * super(xxx) :访问父类的有参构造方法 * 这些super一定是在子类构造方法中的第一句话
-
-
解决方案3:
-
保证子类的所有的构造方法某一个构造方法,让父类初始化完毕即可;
-
先通过子类的无参构造方法里面---this(xxx):访问本类(子类)有参构造方法
-
再子类的有参构造方法的第一话:让父类初始化 super(xxx):间接访问父类的有参构造方法
-
子类继承父类,一定要先执行父类的构造方法,初始化完毕之后;然后才能执行子类的构造方法---分层初始化
-
-
-
注意: 子类在隐藏了一个super(),所以先要访问父类构造方法,在执行子类,如果有super(xxx),则super()不自动创建
- 子类继承父类,成员变量的访问问题:
- 情况1: 子类和父类的中成员变量名称不一致,访问时,只要分别访问即可
- 情况2: 子类和父类的成员变量名称一致,访问时:
- 先在子类的局部位置找,有没有这个变量,如果有就使用
- 要是没有,在子类成员位置中继续找,有没有这个变量,如果有就使用
- 要是子类的成员位置也没有,那么会在父类的成员位置继续找,看有没有这个变量,有的话就使用
- 如果父类的成员位置同样还没有的话,则会报错(前提:这个父类没有它的父类了),说明整个子父类中都没有变量
- 遵循"就近原则"
如果是向上转型的时候,父类名 对象名 = new 子类名; ---- > 成员变量输出为父类的值
//父类 class Person{ int age = 20; } //子类 class Man extends Person{ int age = 40; } public class Test{ public static void main(String[] args){ Person person = new Man(); System.out.println(person.age); //20 } }
想要输出子类成员变量值需要用到向下转型(具体后面会分析)
-
子类继承父类,关于成员方法的访问:
-
情况1:子类和父类的成员方法名称不一致,调用时,只要分别调用就可以
-
情况2:子类和父类的成员方法一模一样时(权限修饰符,返回值类型,参数列表都一样)
- 子类将父类的方法覆盖了---->方法重写 :Override---->子类在父类的基础上,将父类的覆盖了,使用自己的功能;
public class Person { //确定属性 private String name; private int age; private String professional; //无参 public Person() { } //有参 public Person(String name, int age, String professional) { this.name = name; this.age = age; this.professional = professional; } ... ... //定义方法 public void eat(){ System.out.println("都喜欢吃"); } public void show(){ System.out.println("姓名:" + name + "\n" + "年龄:" + age + "\n" + "职业:" + professional); } } //子类 public class SourthPerson extends Person{ public SourthPerson() { } ... ... @Override //重写 public void eat() { System.out.println("南方人喜欢吃大白米饭"); } } //测试类 public class PersonTest { public static void main(String[] args) { //无参--南方 SourthPerson sourthPerson = new SourthPerson(); sourthPerson.setName("张三"); sourthPerson.setAge(33); sourthPerson.setProfessional("商人"); sourthPerson.show(); sourthPerson.eat(); sourthPerson.favorite(); } }
-
补充:
类加载的时候,内存是很快的(继承关系)
父类和子类与静态相关的先执行
静态的东西优先于对象存在 (类名 对象名 = new 类名() 😉
静态代码块>构造代码块>构造方法…
继承关系:分层初始化---->先父类初始化----然后才是子类初始化
class Fu2{ static{ System.out.println("Fu2的静态代码块");//1) } public Fu2(){ System.out.println("Fu2的无参构造方法");//4) } { System.out.println("Fu2的构造代码块"); //3) } } class Zi2 extends Fu2{ public Zi2(){ System.out.println("Zi2的无参构造方法");//6) } { System.out.println("Zi2的构造代码块"); //5) } static{ System.out.println("Zi2的静态代码块"); //2) } } //看程序,写结果 public class Test { public static void main(String[] args) { //创建子类对象 Zi2 z = new Zi2() ; } }
6.final关键字
- final:最终的,不可被更改的,状态修饰符,被final修饰的成员方法,不能被重写,保证父类方法的安全性
class Father{
// public void function(){
public final void function(){
System.out.println("这个文件不能被修改");
}
}
//子类继承父类
class Son extends Father{
public void function(){
System.out.println("这是废弃的文件");
//这里会报错
//'function()' cannot override 'function()' in 'com.hwq.Father'; overridden method is final
//被重写的方法是最终的,但是父类有了final导致不能被覆盖
}
//测试类
public class FinalDemo {
public static void main(String[] args) {
//创建子类对象
Son son = new Son() ;
son.function();
}
}
- 特点: 最终的,无法被修改
- final可以修饰类,该类不能被继承
- final修饰成员方法,此时这个方法不能被子类重写,目的是为了保证方法中某些数据的安全性
- final可以修饰变量,此时这个变量是一个"常量",常驻内存;
- 自定义常量:在开发中,定义一个int类型的
- public static final 数据类型 xxx = 值;// 自定义常量: 编译时期常量,不需要加载;jvm检查语法即可
- 自定义常量:在开发中,定义一个int类型的