构造器
什么是构造器
在类中用来创建对象那个的方法称之为构造器 构造函数 构造方法
注意事项
1:构造器是一个特殊的方法:
a:方法名称和类名相同
b:方法无返回值
c:在方法中无须显示return返回数据
d:构造器是允许方法重载的
e:所有类默认情况下都会存在一个无参构造器,如果在当前类中显式的声明了构造器之后,无参构造器就不存在了
构造器的作用
构造器的作用就是用来创建对象的
- 构造器的调用只能通过new关键词去调用
- 当给一个类中的成员变量的类型声明为基本数据类型之后,导致基本数据类型存在默认值。
- 未赋值的情况下存在值,后续的逻辑可能存在问题。
代码
/**
* 找共性:
* 成员变量(属性) 姓名 学号 性别 班级
* 方法(功能) 学习
*/
public class Student {
static int count = 1;
int id;
String name;
int gender;// 0 代表男 1代表女
String clz;
public Student() {
this("张三");
System.out.println("我被调用了。。。。");
//study();
}
public Student(String name) {
this.name = name;
}
public Student(String name,int gender) {
this(name,gender,count++,"0708");
}
public Student(String name,int gender,int id,String clz) {
this.name = name;
this.gender = gender;
this.id = id;
this.clz = clz;
}
public void study() {
System.out.println(this.name+"day day up");
System.out.println(this.info());
}
public String info() {
return "Student[id:"+this.id+",name:"+this.name+""
+ ",gender:"+(this.gender==0?"男":"女")+",clz:"+this.clz+"]";
}
}
引用类型进过方法
- 基本数据类型经过方法之后 其值不变。值传递
- 引用数据类型进过方法之后 其值会变,值传递(地址值)
- 通过两个变量指向了同一个内存地址,一个对内存进行改变 另一个可见
public class Test02 {
public static void main(String[] args) {
int num = 10;
change(num);
System.out.println("main:"+num);
//声明一个dog对象
Dog d = new Dog();
d.color = "白色";
d.name = "张二狗";
System.out.println(d.info());
change(d);
System.out.println("main:"+d.info());
}
public static void change(int num) {
num++;
System.out.println("change:"+num);
}
public static void change(Dog dog) {
dog.name = "旺财";
dog.color = "黄色";
System.out.println("change:"+dog.info());
}
}
class Dog{
String name;
String color;
public Dog() {
}
public void run() {
System.out.println("run。。。。。");
}
public String info() {
return "name:"+this.name+",color"+this.color;
}
}
继承
继承的优势
- 在一定程度上提高了代码的复用性
什么是继承
- 子承父业, 将多个类中的共性再一次抽取,可以抽取为一个父类。父类的作用就是用来将一些重复的内容不再多次编写(提高代码复用性)
继承的编写
- 子类 extends 父类 (子类拥有父类中的所有的属性以及方法)
继承的注意事项
-
java中只支持单继承 一个子类有且只能有一个父类 复用性的提高是有限的
-
Q:多继承好还是单继承好?
多继承 :极大提高代码复用性 但是代码调用的复杂度也提升了 单继承:代码调用的复杂度比较低,但是复用性比较有限
假设在应用场景中:
A->B 后期随着业务不断扩展,导致A需要继承C时一般的解决办法:A->B->C
但是该种解决办法随着后期业务的不断升级,导致整个继承连会变得极其复杂,既不利于后期维护以及拓展。
所以,能不能用继承就别用继承。
代码
Person类 主类:
package com.mage.oop.extend;
public class Person {
String name;
int age;
int gender;
public Person() {
}
public void eat() {
System.out.println(this.name+"在吃饭");
}
}
Student 类 子类:
package com.mage.oop.extend;
public class Student extends Person{
int id;
public Student() {
}
public void study() {
System.out.println(this.name+"在学习");
}
}
Teacher类 子类:
package com.mage.oop.extend;
public class Teacher extends Person{
double sal;
public Teacher() {
}
public void working() {
System.out.println(this.name+"在工作");
}
}
Test类 测试:
public class Test {
public static void main(String[] args) {
//创建一个学生对象
Student stu = new Student();
stu.name = "小鱼鱼";
stu.eat();
stu.study();
//创建一个老师对象
Teacher t = new Teacher();
t.name = "老薛";
t.sal = 1000000000;
t.eat();
t.working();
}
}
this&super
this
this的用法:
1. this.
当前对象的-》 谁在调用 代表谁
- 可省略:
不需要区分区分同名变量,局部变量和成员变量的时候可以省略 - 不可省略:
区分同名变量,局部变量和成员变量不可以省略
\\为了区分同名变量这里的this 不能省略
public Student(String name) {
this.name = name;
}
2. this()
- 构造器之间的互相调用
- this()一定要在构造器的首行
super
-
当创建子类对象时 会先执行父类的构造器
-
super: 和this的用法一模一样
-
super.
表示当前对象的父类对象的
1.super.
- 可省略的:
super和this的用法是重复的 都可以省略 - super. 不可省略
如果子类和父类中出现了同名变量或者是同名方法
2.super()
-
调用父类的构造器,默认情况下调用的父类的无参构造器(默认情况下每个类中都存再一个无参构造器 哪怕不写也存在)
-
当父类中存在其他构造器时,无参构造器不存在,此时如果再子类中没有通过super()显示的指定调用的构造器会导致程序报错。
-
在构造器中this()和super()不能同时出现,如果两个都不存在,默认是存在的super()。
代码
public class Test01 {
public static void main(String[] args) {
// 创建一个子类对象
Dog d = new Dog();
//d.lookDoor();
}
}
class Animal{
String name;
public Animal() { System.out.println(" Animal 我被调用了......."); }
public Animal(String name) {
this.name = name;
System.out.println(" Animal 带参构造器 我被调用了.......");
}
public void eat() {
System.out.println("animal 吃东西");
}
}
class Dog extends Animal{
String nickName;
public Dog() {
this("呵呵");
System.out.println(" DOG 我被调用了。。。");
}
public Dog(String nickName) {
//super("hehe");
this.nickName = nickName;
System.out.println("DOG 才参数的");
}
public void lookDoor() {
System.out.println("看门");
super.eat();
}
public void eat() {
System.out.println("dog 吃东西");
}
}
重写方法
定义
在子类中定义了和父类中同名的方法 我们将该方法称之为重写方法(覆盖)
为什么需要重写?
父类的功能不能满足子类的需求。子类在父类的基础上进行了扩展。
如何确定一个方法是重写方法?
在子类的方法上加入@Overried 注解 如果不报错 证明是重写
重写的前提:
- 一定要发生继承关系。并且子类的方法名和父类的方法名同名
- 参数列表要一样
- 返回类型要一样
代码
public class Test03 {
public static void main(String[] args) {
//创建一个子类对象
S s = new S();
s.study();
s.marry();
s.work();
}
}
/**
* 爱情观
*
*/
class F{
String name;
public F() {
}
public int study() {
System.out.println("好好学习 时间观念及其严苛");
return 1;
}
public void marry() {
System.out.println("赶紧结婚 我要抱孙子");
}
public void work() {
System.out.println("赶紧去挣奶粉钱。。。。。");
}
}
class S extends F{
public S() {
}
@Override
public int study() {
System.out.println("开心很重要 开心的学习");
return 1;
}
}
object类
什么是object
Object: 是所有类的根基类 超类 父类
当一个类没有显式的继承关系的时候,默认情况下他的父类都是Object
- Object:
ctrl+O 罗列当前类中的所有方法
finalize: gc回收垃圾时 自动调用finalize
wait
notify
notifyAll
--- 学习多线程时候会讲
clone: 克隆 (创建对象的一种方式 深浅复制)
hashCode: 哈希码 -> 哈希算法 唯一的值
getClass:获取当前类的Class对象 反射
- 输出一个对象的时候默认情况下会调用当前对象的toString
==与equals的区别
- == 比较基本数据类型比较的是值 比较引用类型比较的是地址
- equals:用来比较相等的 如果相等返回true 反之返回false
- Object中的比较是通过==比较的
代码
public class Test04 {
public static void main(String[] args) {
//创建一个Test04 对象
Test04 t = new Test04();
//创建一个Bird对象
Bird b = new Bird();
System.out.println(b);
System.out.println(b.toString());
// 创建一个bird对象
Bird b1 = new Bird();
// 比较相等的
boolean flag = b.equals(b1);
System.out.println(flag);
}
}
class Bird{
String color;
String type;
public Bird() {
}
@Override
public String toString() {
return "Bird{color:"+this.color+",type:"+this.type+"}";
}
}
封装
四个修饰符
- public 修饰的人见人爱型 都能访问 被public修饰的方法、类、变量能被所有类可见
- protected 同包下可见 异包下子类可见
- 默认的: 不写 远亲不如近邻 同包下可见 异包下不可见
- private: 自私自利 本类可见
本类 | 同包下子类 | 同包下无关类 | 异包子类 | 异包无关类 | |
---|---|---|---|---|---|
public | √ | √ | √ | √ | √ |
protected | √ | √ | √ | √ | × |
默认的 | √ | √ | √ | × | × |
private | √ | × | × | × | × |
代码
本类
package com.mage.oop.box.china;
public class F {
public String name;
public static void main(String[] args) {
F f = new F();
System.out.println(f.name);
}
}
同包下无关类
package com.mage.oop.box.china;
public class LaoWang {
private String name;
public static void main(String[] args) {
LaoWang f = new LaoWang();
System.out.println(f.name);
}
}
同包下子类
public class S1 extends F{
public static void main(String[] args) {
S1 s = new S1();
System.out.println("通过同包下的子类对象方法父类中的public修饰的变量:"+s.name);
}
}
异包下无关类
package com.mage.oop.box.EN;
import com.mage.oop.box.china.F;
public class LaoWang2 {
public static void main(String[] args) {
F f = new F();
System.out.println("异包下的不同类访问public修饰的变量:"+f.name);
}
}
异包下子类
package com.mage.oop.box.EN;
import com.mage.oop.box.china.F;
/*
* 如果某个类要使用时 该类不在当前包下 需要导包 import 包名.类名;
*/
public class S2 extends F {
public static void main(String[] args) {
S2 s = new S2();
System.out.println("异包下的子类对象访问父类中public修饰的变量:"+s.name);
}
}
修饰变量
局部变量只能通过final修饰
- 1:将类中的成员变量通过public 默认的 protected 修饰之后,导致在某些情况下 可以随意.出来。这些修饰符修饰的变量不够安全。
- 2:将这些变量通过private 修饰。但是导致无法正常访问
代码
public class Test01 {
public static void main(String[] args) {
// 创建一个Student
Student stu = new Student();
//stu.age = 100;
//System.out.println("stu的年龄是:"+stu.age);
stu.setGender(3);
System.out.println("stu的年龄是:"+stu.getGender());
}
}
class Student{
private int gender;
private int age;
public Student() {
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class ArrayList{
private int size;// 实际存储容量
private int capacity;// 实际数组容量
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
修饰方法
修饰符的作用是用来屏蔽一些底层的实现逻辑,降低调用者(程序员)的复杂度。确保当前类更加安全。
修饰符可以修饰 类
- 属性(成员变量) :
避免随意.属性,修改获取属性 造成数据不安全
如果用private修饰的话 一定要保证对外提供get、set方法让外部可见方法 - 屏蔽底层调用细节,降低调用者(程序员)的复杂度 使得代码更加健壮
- public private 比较常用
代码
计算水仙花数
package com.mage.oop.test;
public class FlowerUtil {
public static boolean isFlower(int num) {
//获取累加的和
int sum = sum(num);
return num==sum;
}
private static int sum(int num) {
//声明存放累加的结果
int result = 0;
// 声明一个方法 计算一个数字的长度 位数
int length = length(num);
while(num!=0) {
//分离每一位
int bit = num%10;
result = result+pow(bit,length);
num = num/10;
}
return result;
}
public static int pow(int bit,int length) {
int result = 1;
for(int i = 1;i<=length;i++) {
result = result*bit;
}
return result;
}
public static int length(int num) {
int length = 0;
while(num!=0) {
num = num/10;
length++;
}
return length;
}
}