//父类
public class person {
int age;
String name;
int sex;
public void showInfo() {
System.out.println(this.age);
System.out.println(this.name);
System.out.println(this.sex);
}
}
//子类
public class student extends person{
String school;
public void showInfo() {
System.out.println(this.age);
System.out.println(this.name);
System.out.println(this.sex);
System.out.println(this.school);
}
}
子类不是父类的子集,而是对父类的“扩展”
子类不能访问父类中私有的成员变量
Java只支持单继承,不允许多重继承(一个子类只能有一个父类,一个父类可以派生多个子类)
//父类
public class ManKind {
int salary;
int sex;
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public void manOrwomen() {
if(this.sex == 1) {
System.out.println("man");
}else if(this.sex == 0) {
System.out.println("woman");
}
}
public void employeed() {
if(this.salary == 0) {
System.out.println("no job");
}else {
System.out.println("job");
}
}
}
//子类
public class Kids extends ManKind{
int yearsOld;
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge() {
System.out.println(this.yearsOld);
}
public static void main(String[] args) {
Kids somekid = new Kids();
somekid.setSalary(1000);
somekid.setSex(0);
somekid.setYearsOld(20);
somekid.manOrwomen();
somekid.employeed();
somekid.printAge();
}
}
2.方法的重写(覆盖)
注:
-
子类重写父类的方法,只是重写编写方法体的代码
-
如果父类的方法是public的,子类重写的时候不能使用缺省以下的修饰符
方法的重载:一个类可以有多个同名方法。
方法的重写:子类可以重新写父类的方法,覆盖父类的方法。
3.关键字:supersuper可用于访问父类中定义的属性和成员方法,可用于在子类构造方法中调用父类的构造器。
当子父类出现同名成员时,可以用super进行区分。
使用super,子类可以调用子类之上的所有父类层级。
//父
public class ManKind {
int salary;
int sex;
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public void manOrwomen() {
if(this.sex == 1) {
System.out.println("man");
}else if(this.sex == 0) {
System.out.println("woman");
}
}
public void employeed() {
if(this.salary == 0) {
System.out.println("no job");
}else {
System.out.println("job");
}
}
}
//子
public class Kids extends ManKind{
int yearsOld;
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge() {
System.out.println(this.yearsOld);
}
public static void main(String[] args) {
Kids somekid = new Kids();
somekid.setSalary(1000);
somekid.setSex(0);
somekid.setYearsOld(20);
somekid.manOrwomen();
somekid.employeed();
somekid.printAge();
}
}
//孙
public class Kkids extends Kids{
public void test() {
super.salary = 1;//super向上追溯父类的父类
super.yearsOld = 20;//super直接追溯父类的成员变量
super.employeed();//super直接追溯使用父类的成员方法
super.manOrwomen();//super向上追溯父类的父类成员方法
}
}
子类中所有的构造器默认都会访问父类中空参数的构造器
//父
public class Fu{
public Fu(){
Systemout.println("我爸是我爸,我是我爸儿。");
}
}
//子
public class Zi extends Fu{
public static void main(String[] args){
Zi z = new Zi();//new Zi()是在调用Zi类的默认无参构造方法,在这个过程中就会使用到父类的无参构造
}
}
//此时运行子类会默认输出“我爸是我爸,我是我爸儿”
在父类只有有参构造时,子类必须显示构建一个构造来调用父类的有参构造,并且调用父类构造方法要写在第一行。
//父
public class Fu{
public Fu(int a, int b){
this.a = a;
this.b = b;
}
int a;
int b;
}
//子
public class Zi extends Fu{
public Zi(int a, int b){
super(a,b);
}
}
如果子类构造器中既未显示调用父类或本类的构造器,而父类中有有参的构造器,则编译出错。
this和super的区别| No. | 区别 | this | super |
|---|---|---|---|
| 1 | 访问属性 | 访问本类中的属性,如果本类中没有此属性则从父类继续查找 | 访问父类中的属性 |
| 2 | 调用方法 | 访问本类中的方法 | 直接访问父级中的方法 |
| 3 | 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 访问父类中的构造器,必须放在子类构造器的首行 |
| 4 | 特殊 | 表示当前对象 | 无此概念 |
-
多态性在Java中的体现:
-
方法的重载(相同的名称方法实现不同的逻辑)和重写(子类对父类方法的覆盖)
-
对象的多态性——直接应用在抽象类和接口上
-
-
Java引用变量有两种类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
-
若编译时类型和运行时类型不一致,就出现多态(对象的多态)。
-
向上转型:把子类的对象给父类的类型的变量引用
public class person{
}
public class student extends person{
public static void main(String[] args){
person e = new student();//父类的引用对象可以指向子类的实例,但父类的引用对象e不能访问子类中添加的属性和方法
//Object类的对象可以指向任何子类的实例
Object o = new person();
Object o = new student();
person p = new person();
p = new student();
}
}
父类的引用对象e不能访问子类中添加的属性和方法。
//父
public class person{
public void showInfo(){
}
}
//子
public class student{
public void showInfo(){
}
public static void main(String[] args){
person p = new person();
p.showInfo();//调用父类showInfo方法
student s = new student();
s.showInfo();//调用子类showInfo方法
person e = new student();
e.showInfo();//调用的是子类的showInfo方法
}
}
对于上述代码,编译时e为person类型,而方法的调用是在运行时确定的,所以调用的是student类的showInfo()方法。——对象绑定。
6.x instanceof Ax instanceof A:检验x是否为类A的对象,返回值为boolean型。
//父
public class person{
}
//子
public class student{
public static void main(String[] args){
student s = new student();
person p = new person();
person e = new student();
System.out.println(s instanceof person);//true
System.out.println(p instanceof person);//true
System.out.println(p instanceof student);//false
System.out.println(e instanceof student);//true
}
}
7.Object类
Object类是所有Java类的根父类(基类)。
如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类。
public void test{
public void test(Object obj){
//给test方法设置一个形参参数,这个参数不确定到底会传进来一个什么类型,这时可以设置为Object类,可以接收任何类型的参数
}
}
| NO. | 方法名称 | 类型 | 描述 |
|---|---|---|---|
| 1 | public Object() | 构造 | 构造方法 |
| 2 | a.equals(b) | 普通 | 比较引用对象是否相同 |
| 3 | Object o = new Object(); System.out.println(o.hashCode()); | 普通 | 获取Hash码 |
| 4 | System.out.println(p.toString()); | 普通 | 打印对象内存地址 |
Object类是所有类的父类,所以所有的类都可以使用Object类的方法。
Object类型的对象可以接收任何子类的实例
8.对象类型的转换小的数据类型可以自动转换成大的数据类型:
int i = 10; long l = i;
可以把大的数据类型强制转换成小的数据类型:
long l = 10; int i = (int)l;
//父类
public class Person{
}
//子类
public class Student{
}
//测试类
public class Test{
public static void main(String[] args){
Student s = new Student();
Person p = s;//子类到父类的类型转换可以自动进行
}
Person p = new Person();
Student s = (Student) p;//父类到子类的类型转换需要强制进行
}
无继承关系的引用类型转换是非法的
String s = "hello"; Object obj = s;//子类到父类的类型转换可以自动进行 Object obj = "hello"; String s = (String) obj;//父类到子类的类型转换需要强制进行
//父类
public class person{
public void test(){
System.out.println("这是person的test方法");
}
}
//子类
public class student extends person{
public void getSchool(){
System.out.println("这是student的getSchool方法");
}
}
//test类
public class test{
public static void main(String[] args){
test t = new test();
t.method(new person());//person
t.method(new student());//student
}
public void method(person e){//先给定person类型参数
if(e instanceof student){
student s = (student) e;//父类到子类,强制转换
s.getSchool();//强制转换类型后可以调用student类的方法
}else{
e.test;//调用person类的方法
}
}
}
9.==操作符与equals方法
public class test{
public static void main(String[] args){
int i = 3;
System.out.println(i == 4);//输出:false
}
person p1 = new person();
person p2 = new person();
System.out.println(p1 == p2);//输出:false,只有指向同一个对象时,==才返回true
System.out.println(p1.equals(p2));//输出:false,只能比较引用类型,其作用与==相同,比较是否指向同一个对象
person p1 = new person();
person p2 = p1;
System.out.println(p1 == p2);//输出:true
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
//对于特殊的类(String、File、Date),使用==比较的是对象(对象的地址),equals比较的是内容
//除了特殊的类之外,==和equals比较的都是对象的内存地址
}
==比较的是对象的内存地址,equals对于特殊类比较的是对象的内容,对于普通类比较的也是对象的地址。
//编写Order类,由int型的orderId和String型的orderName,相应的getter()和setter()方法,两个参数的构造器,重写父类的equals方法,并判断测试类中创建的连个对象是否相等。
public class Order {
public Order(int orderId, String orderName){
this.orderId = orderId;
this.orderName = orderName;
}
int orderId;
String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
@Override//(alt + /) 重写子类覆盖父类的方法
public boolean equals(Object obj) {
boolean flag = false;
if(obj instanceof Order) {
Order o = (Order) obj;//父类到子类的类型转换需要强制进行(Object是父类,现在要做的是将Object类型的变量强制转换成子类Order类型的变量并赋给引用类型变量o)
if(this.orderId == o.orderId && this.orderName.equals(o.orderName)) {
flag = true;
}
}
return flag;
}
}
//测试类
public class test{
public static void main(String[] args){
Order o1 = new Order(123,"a001");
Order o1 = new Order(123,"a001");
System.out.println(o1.equals(o2));
}
}
//覆盖equals方法,判断年月日是否相同
public class MyDate {
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
int year;
int month;
int day;
@Override
public boolean equals(Object obj) {
int flag = 0;
if(obj instanceof MyDate) {
MyDate m = (MyDate)obj;
flag = 0;
if(this.year == m.year) {
flag += 1;
}
if(this.month == m.month) {
flag += 1;
}
if(this.day == m.day) {
flag += 1;
}
}
if(flag == 0) {
return true;
}else {
return false;
}
}
}
//测试类
public class test{
public static void main(String[] args){
MyDate m1 = new MyDate(2021,10,27);
MyDate m2 = new MyDate(2021,10,27);
System.out.println(m1.equals(m2));
}
}
10.包装类和toString
| 基本数据类型 | 包装类 |
|---|---|
| boolean | Boolean |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| char | Character |
| float | Float |
| double | Double |
//基本数据的包装类
Integer i = new Integer(111);
Integer i = new Integer("123");//输出123
Integer i = new Integer("abc");//编译不报错,但运行报错,因为abc无法转int类型
Integer i = new Integer(112);//装箱
int i0 = i.intValue();//拆箱
//java 1.5版本以后
Integer i = 123;//自动装箱
int i0 = i1;//自动拆箱
boolean b = new Boolean("flase").booleanValue();//装箱
boolean b = new Boolean("flase");//自动装箱
boolean b1 = true;//自动拆箱
基本数据类型与字符串之间的转化
//字符串类型转换成基本数据类型——parse
int i = Integer.parseInt("123");
float f = Float.parseFloat("0.12");
boolean b = Boolean.parseBoolean("flase");
//基本数据类型转换成字符串数据类型——valueOf
String istr = String.valueOf(i);
String fstr = String.valueOf(f);
String bstr = String.valueOf(true);
toString
public class a{
public a(int year,int month,int day){
this.year = year;
this.month = month;
this.day = day;
}
int year; int month; int day;
}
//
public class test{
public static void main(String[] args){
a a = new a(2021,10,28);
System.out.println(a.toString);//输出结果为当前对象的内存地址
System.out.println(a);//同上行内容输出相同,都是输出当前对象的内存地址
}
}
//父类的Object的toString方法就是输出当前对象的内存地址
//如果想要输出类的其他信息,可以重写toString方法
public class a{
public a(int year,int month,int day){
this.year = year;
this.month = month;
this.day = day;
}
int year; int month; int day;
@Override
public String toString(){
String str = this.year + "-" + this.month + "-" + this.day;
return str;
}
}
public class test{
public static void main(String[] args){
a a = new a(2021,10,28);
System.out.println(a.toString);//输出:2021-10-28
System.out.println(a);//打印a对象相当于默认执行打印a.toString()
}
}
11.关键字static
当类属性不想因为对象的不同而改变时。将这些属性设置为类属性。
当有些方法不想因为对象的不同而频繁的通过new对象的方式取调用方法时,就写成static方法。
调用时直接 类名.属性 、类名.方法名
public class Chinese{
static String country;//类变量(静态变量),不需要实例化
String name;//实例变量
int age;//实例变量
}
public class test{
public static void main(String[] args){
Chinese.country = "中国";//类变量,类中的所有实例变量的country都是中国
Chinese c = new Chinese();
c0.country = "中国";//默认
c0.name = "xxx";//类的实例化
c0.age = 21;
c1.country = "中国";//
c1.name = "xxx";
c1.age = 22;
c2.country = "中国";//
c2.name = "xxx";
c2.age = 23;
System.out.println(Chinese.country);//类名.属性
}
}
常用static创建工具类
//创建一个工具类判断字符串是否是一个空字符串
public class Utils{
public static boolean isEmpty(String s){
boolean flag = flase;
if(s != null && !s.equals("")){
flag = true;
}
return flag;
}
}
//test
public class test{
public static void main(String[] args){
System.out.println(Utils.isEmpty("21"));//不用new就能直接用
}
}
类变量这种可以被所有实例化对象共享的属性,使用时要慎重,因为只要改一次,所有类都得到变化。
12.单例设计模式设计模式:优选的代码结构、编程风格以及解决问题的思考方式。
单例:只有一个实例化对象,在整个软件系统运行过程中,这个类只被实例化一次,以后不论在哪都只调用这一个实例。
例如实例化对象的创建需要消耗大量的时间和资源时,会用到单例设计模式。
饿汉式单例模式:来了就吃,事先做好
public class Single{
//私有的构造,构造方法私有化,调用这个类的人就不能直接使用new来创建对象
private Single(){
}
//私有的* Single类型的 类变量*
private static Single s = new Single();
public static Single getInstance(){
return s;
}
}
//test
public class test{
public static void main(String[] args){
Single s = new Single();//报错
Single s0 = Single.getInstance();
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
Single s3 = Single.getInstance();
Single s4 = Single.getInstance();
//这些过程new Single()只发生了一次
}
}
懒汉式单例模式:最开始对象时null,直到有第一个人调用我,才new一个对象,之后所有调用我的都用这个对象
public class Single1{
//私有化构造方法,让外界不能直接new对象
private single(){
}
private static Single1 s1 = new null;
public static Single1 getInstance(){
if(s1 == null){
s1 = new Single1();
}
return s1;
}
}
//test
public class test{
public static void main(String[] args){
Single1 s0 = Single1.getInstance();
Single1 s1 = Single1.getInstance();
Single1 s2 = Single1.getInstance();
Single1 s3 = Single1.getInstance();
}
}
13.内部类
注:如果内部类时static的,就不能使用外部类的非static的成员
public class Test{
int i;
public int z;
private int k;
class A{
public void setTestFileds(){
Test.this.i = 1;
Test.this.z = 2;
Test.this.k = 3;
}
}
public void setInfo(){
new A().setTestFileds();//外部类想要使用自己的内部类方法,必须先new内部类的对象
}
public void showInfo(){
System.out.println(i);
System.out.println(z);
System.out.println(k);
}
public static void main(String[] args) {
Test t = new Test();
t.setInfo();
t.showInfo();
}
}
可以使用内部类变相的实现类的多重继承
public class Test1 {
public static void main(String[] args) {
Test1 t = new Test1();
//直接A a = new A();提示没有任何类型的Test1的外层实例可访问,这时候只需先new一个类对象,再new内部类
A a = t.new A();
a.testA();
}
class A{
public void testA() {
new InnerB().testB();
new InnerC().testC();
}
private class InnerB extends B{
@Override
public void testB() {
System.out.println("这是重写的testB方法");
}
}
private class InnerC extends C{
@Override
public void testC() {
System.out.println("这是重写的testC方法");
}
}
}
class B{
public void testB() {
}
}
class C{
public void testC() {
}
}
}
14.代码块(含匿名类)
public class Person{
String name;//1
public Person(){//3
this.name = "张三";
System.out.println("执行的是构造方法");
}
//非静态的代码块
{//2
System.out.println("执行的是代码块");
}
}
//再new Person();执行的时候,执行顺序是:
//1.类的属性的默认值初始化和显示初始化
//2.执行代码块的代码
//3.执行构造器的代码
静态代码块:解决复杂的静态变量属性的修改问题
public class Person{
static age;
static a a = new a();
public static void showAge(){
System.out.println(age);
}
static{
//只能使用静态static修饰的属性和方法
age = 1;
showAge();
a.name = "";//静态代码块的作用,修改复杂的静态属性变量
a.i = 1;//静态代码块的作用,修改复杂的静态属性变量
}
}
public class a{
int i;
String name;
}
非静态代码块:负责匿名类属性的初始化工作
public class Person{
String name;
public Person(){
this.name = "张三";
}
}
public class test{
public static void main(String[] args){
Person p =new Person(){//这就是一个Person的匿名子类
//问题:想把name改成李四,但不想动Person的代码
{
//用代码块代替构造方法
super.name = "李四";
}
@Override
public void test(){
System.out.println("===");
}
};//注意分号
System.out.println(p.name);
}
}
//构造一个匿名的Person子类
//匿名类:这种类没有类名,就不能用new方法创建对象,也无法在构造器中初始化属性,这种情况就用代码块{}做初始化工作
15.关键字final
public final class A{
}
class B extends A{
//错误,final修饰的类不能被继承
}
//
public class A{
public final void test(){
}
}
public B extends A{
@Override
public void test(){
//错误,final修饰的方法不能被重写
super.test();
}
}
//
public class A{
final String NAME = "";//final修饰变量是常量,常量必须显示赋值,常用大写
final static String NAME_1 = "";//final static一起修饰变量,就是全局常量
//常量定义名称,约定使用大写,如果多个单词组成名称,用‘_’连接
}
16.抽象类(abstract)
必须靠继承实现抽象的方法
public abstract class Animal {
public abstract void test();//抽象类,没有具体的方法
public abstract void move();
}
class Dog extends Animal{
@Override
public void move() {
System.out.println("狗的移动方式是跑");
}@Override
public void test() {
// TODO 自动生成的方法存根
}
}
class Fish extends Animal{
@Override
public void move() {
System.out.println("鱼的移动方式是游");
}@Override
public void test() {
// TODO 自动生成的方法存根
}
}
abstract class Bird extends Animal{//只要有一个抽象方法,类就必须是抽象类,抽象类可以继承抽象类
@Override
public void move() {
// TODO 自动生成的方法存根
}
public abstract void test();
}
//test
public class Test2 {
public static void main(String[] args) {
Dog d = new Dog();
d.move();
}
}
只要类中有一个方法是抽象方法,类就必须是抽象类。
抽象类可以继承抽象类
接口可以继承接口
17.模板设计模式抽象类就像一个大纲,里面的抽象方法就是每个章节的标题。子类根据这些标题把每个章节写出来。
public abstract class Template{
public abstract void code();
public final void getTime(){
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("code方法的执行时间:" + (end - start));
}
}
class TestTmp extends Template{
@Override
public void code(){
int k = 0;
for(int i = 0; i<=100; i++){
k+ = 1;
}
System.out.println(k);
}
}
//
public class Test{
public static void main(String[] args){
TestTmp t = new TestTmp();
t.getTime();
}
}
//输出的结果是code方法执行所需的时间
18.接口(implements)
接口是一种特殊的抽象类。解决单继承的局限。
接口的特点:
-
用interface定义
-
接口中所有的成员变量都默认是由public static final(全局常量)修饰的
-
接口中所有的方法都默认是由public abstrace(抽象方法)修饰的
-
接口没有构造器
-
接口采用多层继承机制
接口可以继承接口
//接口1
public interface TestIn1 {
int i = 1;//等同于public static final int i = 1;
void test1();//等同于public abstrct void test();
}
//接口2
public interface TestIn2 {
void test2();
}
//类
public class TestInImpl implements TestIn1,TestIn2{
@Override
public void test()1 {
// TODO 自动生成的方法存根
}
@Override
public void test1()2 {
// TODO 自动生成的方法存根
}
}
如果一个类既继承父类,又实现接口,那么先继承,再实现。
接口的主要作用在于扩展(修改)父类,方便父类的子类自动修改接口所添加的方法而不是逐一在子类中修改。
public abstract class Person{
int age;
String name;
int sex;
public abstract void showInfo();
}
//
public interface Cooking{
void fry();
}
//
public interface Singing{
void singing();
}
//会唱歌的厨子是一个老师
public class SCTercher extends Person implements Cooking,Singing{
String course;
public void setInfo(){
super.age = 27;
super.name = "张三";
super.sex = 0;
this.course = "英语";
}
@Override
public void showInfo(){
System.out.println("会唱歌的厨子的老师的信息是:");
System.out.println(super.age);
System.out.println(super.name);
System.out.println(super.sex);
System.out.println(this.course);
}
@Override
public void fry(){
}
@Override
public void singsing(){
}
}
//test
public class Test{
public static void main(String[] args){
SCTeacher sct = new SCTeacher();
sct.setInfo();
sct.showInfo();
}
}
接口和抽象类的区别
抽象类是对于一类事物的高度抽象,其中既有属性的抽象也有方法的抽象。
接口是对方法的抽象,也就是对一系列动作的抽象。
当需要对一类事物抽象的时候,应该使用抽象类形成一个父类。
当需要对一系列动作抽象的时候,就使用接口,需要使用这些动作的类去实现相应的接口即可。
19.工厂方法(FactoryMethod) 20.面向对象内容小结


