提示:面向对象笔记
文章目录
前言
提示:花了一个星期整理的java笔记
提示:以下是本篇文章正文内容,下面案例可供参考
对象和类
区别
- 面向过程编程:一堆方法,调来调去
- 面向对象编程:是以对象未核心,围绕着对象做操作
- 面向接口编程:面向对象的基础,抽接口
- 面向对象的优点:复用性好,可维护性好、可扩展性好、移植性好
- 面向过程:实在
- 面向对象:抽象
难点
- 学完面向对象晕是正常的--------多练、多想
- 不晕两种情况:1、什么都不懂 2、以为自己不晕—语法掌握
- 6天:掌握语法,知道何时用
- 完成打飞机小游戏—面向对象6天内容实际的应用
面向过程的缺点
- 缺乏对象数据的封装
- 数据和方法是分离状态
package com.lagu.homwork2.com.danei.review.taks1;
public class mianxiangguocheng1 {
public static void print(String name,int age,char gender,double salary){
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("性别:" + gender);
System.out.println("工资:" + salary);
}
public static void main(String[] args) {
String name = "张三";
int age = 25;
char gender = '男';
double sal = 5000;
print(name,age,gender,sal);
System.out.println("----------------------");
String a = "abc";
int b = -1000;
char c = '国';
double d = -1000;
print(a,b,c,d);
}
}
//四个原元素谁都可以调用,且相互独立
- 而面向对象 可以使用抽象数据类型来解决
抽象数据类型
抽象数据类型可以理解为:将不同类型的数据的集合组成一个整体用来描述一种新的事物;
将name,age,gender,salary— 包到一种类型中
什么是类1
- 类定义了一种抽象数据类型。
- 类不但定义了抽象数据类型的组成(成员变量),同时还定义了可以对该类型实施的操作(方法)。
例如:
/**
* 定义雇员类
*/
public class Emp {
String name;
int age;
char gender;
double salary;
public static void printEmp(Emp emp){
System.out.println("姓名:" + emp.name);
System.out.println("年龄:" + emp.age);
System.out.println("性别:" + emp.gender);
System.out.println("工资:" + emp.salary);
}
public static void main(String[] args) {
//使用new 关键字创建Emp类型的对象
Emp emp1 = new Emp(); // emp1 可以看成对象(实际上是引用)
//为该对象的各个成员变量赋值
emp1.name = "abc";
emp1.age = 25;
//使用该对象调用
printEmp(emp1);
emp1.salary = 15000;
printEmp(emp1);
}
}
什么是类2
- 定义了Emp类以后,提升了代码的模块化以及代码的重用性,但程序依然存在问题:打印信息的方法只能针对Emp数据操作,属于Emp自身的方法,需要实现数据和方法(对该类数的操作)的统一。
改进3.0
/**
* 定义雇员类
*/
public class Emp {
String name;
int age;
char gender;
double salary;
//打印员工信息的方法定义在类中,知道对象成员变量进行操作
public void printEmp(){
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("性别:" + gender);
System.out.println("工资:" + salary);
}
public static void main(String[] args) {
//使用new 关键字创建Emp类型的对象
Emp emp1 = new Emp(); // emp1 可以看成对象(实际上是引用)
//为该对象的各个成员变量赋值
emp1.name = "abc";
emp1.age = 25;
emp1.printEmp();
emp1.salary = 1;
emp1.printEmp();
}
}
小结
- 现实世界是由很多对象(真实存在的事物:人、笔记本)组成的
- 现实世界是现有对象,( 根据共同特征)再抽出类 。
代码中是先创建类再创建对象
类 | 对象 |
---|---|
月饼 | 月饼模子 |
图纸 | 高楼 |
/**
*学生管理系统
对象:学生、老师、课程
抽出类:学生类、老师类、课程类
*/
class Student{ //学生类
}
class Teacher{//老师类
}
class Cla{//课程类
}
- 创建对象的语法:类名 对象名 = new 类名();
Scanner sc = new Scanner(System.in);
Random rand = new Random();
- 一个类可以创建多个对象 。同一个类的多个对象,结构相同,数据不同。
- 类是一种数据类型
只能包含:
1)对象所共有的特征:
属性------静的
2)对象所共有的特征:
行为------动的
什么是类3
- 类是一个**概念(名词)**抽象的定义。简单说就是分类。
- 类定义了该类型的数据结构,称之为“成员变量”,同时,也定义了一些可以被调用的功能,称之为“方法”。
- 类是用于构建对象的模板,对象的实质就是内存中一块存储区域,其数据结构由定义它的类来决定。
class Point{
int x;
int y;
}
类的定义——成员变量
- java语言中,类的成员变量的定义可以使用如下语法:
class 类名{
成员变量类型 变量名称;
...
}
成员变量的初始化
- 对象创建后,其成员变量可以按照默认的方式初始化;对象成员变量的默认初始化值规则如下表
定义类的方法
- 类中除了定义成员变量,还可以定义方法,用于描述对象的行为,封装对象的功能。
- java语言中,可以按照一下方式定义类中的方法:
class 类名{
修饰词 返回值类型 方法名词([参数列表]){
方法体...
}
...
}
使用new关键字创建对象
- 类定义完成后,可以使用new关键字创建对象。创建对象的过程通常称为实例化。
- new 运算的语法为:
new 类名();
类如 new JFrame()可以创建一个窗体对象。
引用类型
- 除了8钟基本类型外,用类名(接口、数组)声明的变量称为引用类型变量,简称“引用”。
- 引用类型变量钟存储的是某个对象在内存中的地址信息。引用的功能在于访问对象。引用类型变量按照如下方声明:
- 引用是对象的代词
类名 引用类型变量名
Point p = new Point();
p.x = 1;
p.x();
引用类型和基本类型的内存分布
基本类型和引用类型的区别
- 引用类型都是 new 出来的 基本类型是可以之间赋值
- 引用 装的是地址,基本装的是确切的值
- 引用画等号 ---------指向同一个对象 基本画等号 ---- 赋值
- 基本类型的之间画等号------------在于赋值
--------身份复印件 - 引用类型之间画等号---------------在于指向同一个对象
----------房子钥匙
房子:对象
钥匙:引用
复杂/配置了一把钥匙给他
举例
/**
*步骤:
* 1.找对象----许多格子
* 2.抽类----class cell{}
* 3.设计类:
* 1)成员变量- row 行号 col 列号
* 2)方法
*/
public class ELuoSi3 {
int row;
int clo;
void printCell() {
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 10; j++) {
if (15 == i && 6==j){
System.out.print("*" + " ");
}else {
System.out.print("-" + " ");
}
}
System.out.println();
}
}
void drop(){ //下落一个格子
row ++;
}
void moveLeft(int n){//左移clo个各种
clo -= n;
}
String getCellInfo(){ //获取格子的坐标
return row + " " + clo;
}
public static void main(String[] args) {
ELuoSi3 e = new ELuoSi3();
e.clo = 4;
e.row = 5;
e.drop();
e.moveLeft(2);
String s = e.getCellInfo();
System.out.println(s);
ELuoSi3 cc = new ELuoSi3();
String ss = cc.getCellInfo();
System.out.println(ss);
}
}
- 运行结构
开始:
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - * - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
下落后:
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - * - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
左移后:
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - * - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
6 2
- 代码改进:
- //把打印方法里不合理,因为:打印背景墙不是格子的行为。
public class cell5 {
public int row ;
public int col ;
void drop(){
row++;
}
void moveLeft(int n){
col -= n;
}
String get(){
return row +",,,"+col;
}
}
-----------------------------------------------------------------
public class Cell5Test {
//没有把打印放在Cell5方法里是 是因为:打印背景墙不是格子的行为,放在里面不合理
public static void printCell1(cell5 c) { //cell5 c = new cell5();
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 10; j++) {
if (c.row == i && c.col == j) {
System.out.print("*" + " ");
} else {
System.out.print("-" + " ");
}
}
System.out.println();
}
}
public static void main(String[] args) {
cell5 cc = new cell5();
cc.col = 5;
cc.row = 5;
printCell1(cc);
cc.drop();
printCell1(cc);
cc.moveLeft(3);
printCell1(cc);
}
}
null
小结
- new后,成员变量有默认值
- 创建对象语法 :
类名 引用 = new 类名();
其中 new 类名() 是在创建对象
因为对象为数据,所以声明引用来指代数据 - 访问成员变量、访问方法
----通过点来操作,语法:
引用.成员变量
引用.方法名(); - 基本类型值之间画等号 ------ 在赋值
----身份证复印件
引用类型之间画等号------指向同一个对象
----房子钥匙 - null:空,没有指向对象
若引用的值为null,则不能再进行 . 操作
否则会出现 NullPointException异常(空指针异常)
return
- 终结方法 和返回一个值
- return;只是用来终结方法 和停止方法的执行
方法的重载
JVM内存结构
方法区
栈
堆
方法签名
- java规定方法签名必须不一样
- 参数列表不同指的是:顺序、个数、类型不同
编译时会根据签名调用不同的方法
重载的好处
- 让用户调用方法更方便
- java建议: 1个文件只包含1个类型
- java规定:java一个文件中可以包含多个类,但是public 的类只能有一个
- public 修饰的类 必须和文件名相同
举例
- 方法重载
package com.lagu.homwork2.com.danei.review.taks1;
public class cell5 {
public int row ;
public int col ;
void drop(){ //下落一格
row++;
}
void drop(int n){ //下落n格
row += n;
}
void moveLeft(){//左移一格
col--;
}
void moveLeft(int n){//左移n格
col -= n;
}
void moveRight(){//右移一格
col++;
}
void moveRight(int n){//右移n格
col += n;
}
String get(){//返回前 行 和 列
return row +",,,"+col;
}
}
小结
- 方法签名: 方法名+参数列表
- 方法的重载:在一个类中方法名相同,参数列表不同
- 编译器 在编译时根据签名绑定不同方法
构造方法
- 在没有构造方法前
package com.lagu.homwork2.com.danei.review.taks1;
import com.lagou.task10.Student;
public class Student6 {
String name;
int age;
String address;
void study(){}
void sayHi(){
System.out.println(name + " ," + age + " ," + address);
}
void setInfo (String name1,int age1,String address1){//给成员变量赋值
name = name1;
age = age1;
address = address1;
}
}
class StudentTest{
public static void main(String[] args) {
Student6 zs = new Student6();
zs.name = "zhangsan";
zs.age = 25;
zs.address = "河北";
zs.sayHi();
Student6 ls = new Student6();
ls.setInfo("lisi",26,"吉林");
ls.sayHi();
}
}
运行结果:
zhangsan ,25 ,河北
lisi ,26 ,吉林
Process finished with exit code 0
- 作用:常常用于给成员变量初始化
- 与类同名,没有返回值类型
- 构造方法是在创建对象时被自动调用
- 若自己不写构造方法,编译器给个默认的无参构造,若自己写了,则不再提供无参构造
- 构造方可以重载
举例:
import com.lagou.task10.Student;
public class Student6 {
String name;
int age;
String address;
void study(){}
void sayHi(){
System.out.println(name + " ," + age + " ," + address);
}
Student6(){ //无参构造方法
}
Student6(String name1,int age1,String address1){ //有参构造方法
name = name1;
age = age1;
address = address1;
}
}
class StudentTest{
public static void main(String[] args) {
Student6 zs = new Student6();
zs.sayHi();
Student6 ls = new Student6("lisi",26,"东北");
ls.sayHi();
}
}
运行结果:
null ,0 ,null
lisi ,26 ,东北
分析:
Student6 zs = new Student6();
//1.创建了一个对象
//2.调用无参的构造方法
- 若自己不写构造方法,编译器给个默认的无参构造,若自己写了,则不再提供无参构造
import com.lagou.task10.Student;
public class Student6 {
String name;
int age;
String address;
void study(){}
void sayHi(){
System.out.println(name + " ," + age + " ," + address);
}
/*Student6(){ //无参构造方法
}*/
Student6(String name1,int age1,String address1){ //有参构造方法
name = name1;
age = age1;
address = address1;
}
}
class StudentTest{
public static void main(String[] args) {
Student6 zs = new Student6();
zs.sayHi();
Student6 ls = new Student6("lisi",26,"东北");
ls.sayHi();
}
}
运行结果:
Error:(25, 23) java: 无法将类 com.lagu.homwork2.com.danei.review.taks1.Student6中的构造器 Student6应用到给定类型;
需要: java.lang.String,int,java.lang.String
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
this关键字
- this指代当前对象,随调指的就是谁
public class Student6 {
String name;
int age;
String address;
void study(){}
void sayHi(){
System.out.println(name + " ," + age + " ," + address);
}
Student6(){ //无参构造方法
}
Student6(String name,int age,String address){ //有参构造方法
this.name = name;
this.age = age;
this.address = address;
}
}
class StudentTest{
public static void main(String[] args) {
Student6 zs = new Student6();
zs.sayHi();
Student6 ls = new Student6("lisi",26,"东北");
ls.sayHi();
/*
ls.name = "lisi";
ls.age = 26;
ls.address = "东北";
*/
}
}
- 当名字不冲突时,可以省略this
- 用法: this.成员变量----------访问成员变量
this.成员方法----------访问普通方法
this()---------------------调构造方法
void drop(){ //下落一格
row++;
//this.row ++ //c.row++
}
就近原则
public class cell5 {
public int row;
public int col;
cell5(){}
cell5(int row,int col){ //就近原则
row = row;
col = col;
}
}
- 加上this 关键字
public class cell5 {
public int row;
public int col;
cell5(){}
cell5(int row,int col){
this.row = row;
this.col = col;
}
}
public class Student6 {
String name;
int age;
String address;
void study(){}
void sayHi(){
System.out.println(name + " ," + age + " ," + address);
}
Student6(){ //无参构造方法
}
Student6(String name,int age,String address){ //有参构造方法
this.name = name;
this.age = age;
this.address = address;
//this.name ------指的是成员变量
//name------------指的是局部变量/参数
}
}
引用类型数组
- 数组: [ ] 前只要是一个类型就可以
- 引用类型的定义
//声明int类型数组,名为arr,包含4个元素
ar 中每个元素都是int 类型
int [] arr = new int[4]-----基本类型数组
//声明cell型数组,名为arr,包含4个元素
arr 中的每个元素都是cell类型
Cell [] arr = new Cell[4] -----引用类型数组
int是数据类型
cell也是数据类型
Student[] stus = new Student[100];
Random[] rs = new Random[4];
Scanner[] ss = new Scanner[8];
Hero hero = new Hero(); //一个英雄机
//好多子弹 数组
- 引用类型的3种初始化
new之后,arr中每个元素都是0
int[] arr = new int[4];
new之后,cs 中每个元素都是null
cell[] cs = new Cell[4]; //new 在创建数组
cs[0] = new Cell(); //new在创建对象
cs[1] = new Cell(2);
...
Cell[] cs1 = {
new Cell(),
new Cell(),
new Cell(3,4),
new Cell(2,7)
};
Cell[] cs1 = new Cell[]{
new Cell(),
new Cell(),
new Cell(3,4),
new Cell(2,7)
};
- 因为只要 [ ] 前是数据类型就可以
- 数组也是一种数据类型
int [] arr = new int[4];
Cell [] cs = new Cell[4];
声明int[] 类型的数组,名为as,包含4个元素
每个元素,默认值为null
as[0]默认值为null
as[0]是int[] 类型
int[] [] as= new int[4] [];
as[0] = new int[2];
as[0] = new int[4];
as[2] = new int[2];
as[3] = new int[5];
给as中第2个元素的第3个元素赋值为100
as[1][2] = 100;
public class Arras {
public static void main(String[] args) {
int [][] as = new int[4][];
System.out.println(as[0][0]); //空指针异常
//因为 as[0]是int[]类型默认值是null, null.[0] null的.操作会出现指针异常
}
}
运行结果:
Exception in thread "main" java.lang.NullPointerException
改正:
public class Arras {
public static void main(String[] args) {
int [][] as = new int[4][];
as[0] = new int[2];
System.out.println(as[0][0]); //空指针异常
}
}
运行结果:
0
int [][] as = new int[3][];
as[0] = new int[4];
as[1] = new int[4];
as[2] = new int[4];
as[3] = new int[4];
简写:
int [][] as = new int[3][4];
as[0][0] = 100;
as[0][1] = 100;
as[0][2] = 100;
as[0][3] = 100;
as[1][0] = 100;
as[1][1] = 100;
as[1][2] = 100;
as[1][3] = 100;
结论
- 引用类型数组的声明
- 引用类型数组的初始化
- 数组的类型是基本类型数组
把数组写活-arr[i].length
public class Arras {
public static void main(String[] args) {
int [][] as = new int[4][];
as[0] = new int[2];
as[1] = new int[3];
as[2] = new int[1];
as[3] = new int[5];
for(int i=0;i<as.length;i++){
for(int j=0;j<as[i].length;j++){
System.out.print(as[i][j]);
}
System.out.println();
}
}
}
运行结果:
00
000
0
00000
Process finished with exit code 0
小结
- 数组是引用类型,数组对象存在堆中
- 数组类型可以是基本类型数组 也可以是引用类型数组
- 引用类型数组 new 之后每一个类型数组默认初始值为null
练习:
package com.lagu.homwork2.com.danei.review.taks1;
public class Cell {
int row;
int col;
Cell(){}
Cell(int row,int col){
this.row = row;
this.col = col;
}
void drop(){ //下落一行
row++;
}
void moveLeft(){ //左移
col--;
}
void moveRight(){ //右移
col++;
}
String PrintInfo(){ //打印行和列
return row +" ," + col;
}
static class T{
Cell [] cc;
T(int row,int col){
cc = new Cell[4];
cc[0] = new Cell(row,col);
cc[1] = new Cell(row,col+1);
cc[2] = new Cell(row,col+2);
cc[3] = new Cell(row+1,col+1);
}
void drop(){ //下落一格
//cc[0].row++;
for(int i=0;i<cc.length;i++){
cc[i].row++;
}
}
void moveLeft(){ //左移一格
for(int i=0;i<cc.length;i++){
cc[i].col--;
}
}
void moveRight(){
for(int i=0;i<cc.length;i++){
cc[i].col++;
}
}
void print(){
for(int i=0;i<cc.length;i++){
System.out.println(cc[i].PrintInfo());
}
}
}
void printCell(Cell c1){
for(int i=0;i<20;i++){
for(int j=0;j<10;j++){
if(i == c1.row && j==c1.col){
System.out.print("*"+ " ");
}
else {
System.out.print("-" + " ");
}
}
System.out.println();
}
}
public static void main(String[] args) {
//T t = new T(1,1);
Cell c2 = new Cell(4,5);
//c2.printCell(c2);
c2.PrintInfo();
T c3 = new T(1,2);
c3.print();
c3.drop();
System.out.println("下落");
c3.print();
}
}
运行结果:
"C:\Program Files\Java\jdk-11.0.8\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=60285:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\dlz\Desktop\java\out\production\javase com.lagu.homwork2.com.danei.review.taks1.Cell
5 ,5
----------
原始
1 ,2
1 ,3
1 ,4
2 ,3
下落
2 ,2
2 ,3
2 ,4
3 ,3
Process finished with exit code 0
对象内存管理
- 对象内存管理
堆内存
成员变量的声明周期
- 垃圾回收机制
java内存泄漏问题
- 回收没有被引用指向的对象
- system.gc()方法
小结
- 堆中装的是 new出来的对象、数组(包括成员变量)
- 成员变量生命周期,创建对象时存在,对象被回收时消失
- 垃圾回收器(gc)不定时回收没有引用指向的对象,回收过程透明,想快些调用System.gc() 方法
- 内存泄漏:不再使用的对象未被及时回收 ,建议对象不用,引用为null
栈区
- 栈区用于存放方法中的局部变量
- 局部变量的声明周期
成员变量和局部变量区别
小结
- 栈用于存储所有局部变量
- 调用方法时,栈中分配改方法的栈帧 。栈帧中包括 参数及(方法的)局部变量。方法执行结束,栈帧被清除,局部变量失效。
方法区
-
方法区用于存放类的信息
-
程序编译后 产生 类.class字节码文件,被存放在方法区
- 方法只有一份
小结
- 方法区:存储 类的信息— .class 及方法
- 方法只有1份,通过 this 区分对象
继承
-
继承:避免重复的代码
父类中包含所有子类公有的数据
子类中包含子类所特有的数据 -
泛化的过程
把公共的抽出父类
extends关键字
- 继承具有传递性
this() 调用构造方法
package com.lagu.homwork2.com.danei.review.task3;
public class TetorminorTest {
public static void main(String[] args) {
T t = new T();
t.drop();
t.print();
printCell(t);
O oo = new O(5,5);
oo.print();
printCell(oo);
}
public static void printCell(T t){ // 放在测试类合适:不属于父类和子类的行为
for (int i=0;i<20;i++){
for(int j=0;j<10;j++){
boolean flag = true; //默认打 -
for(int k=0;k<4;k++) {
if (i == t.cells[k].row && j == t.cells[k].col) {
flag = false;
System.out.print("* ");
break;
}
}
if(flag){
System.out.print("- ");
}
}
System.out.println();
}
}
public static void printCell(O t){ // 放在测试类合适:不属于父类和子类的行为
for (int i=0;i<20;i++){
for(int j=0;j<10;j++){
boolean flag = true; //默认打 -
for(int k=0;k<4;k++) {
if (i == t.cells[k].row && j == t.cells[k].col) {
flag = false;
System.out.print("* ");
break;
}
}
if(flag){
System.out.print("- ");
}
}
System.out.println();
}
}
}
class Tetorminor {
cell[] cells;
Tetorminor(){
cells = new cell[4];
}
void drop() {
for (int i = 0; i < cells.length; i++) {
cells[i].row++;
}
}
void moveLeft() {
for (int i = 0; i < cells.length; i++) {
cells[i].col--;
}
}
void moveRight() {
for (int i = 0; i < cells.length; i++) {
cells[i].row++;
}
}
void print() {
for (int i = 0; i < cells.length; i++) {
System.out.println(cells[i].printInfo());
}
}
}
class T extends Tetorminor {
T(){this(0,0); }
T(int col,int row){
super();
cells = new cell[4];
cells[0] = new cell(row,col);
cells[1] = new cell(row,col+1);
cells[2] = new cell(row,col+2);
cells[3] = new cell(row+1,col+1);
}
}
class O extends Tetorminor{
O(){this(0,0);}
O(int col,int row){
cells = new cell[4];
cells[0] = new cell(row,col);
cells[1] = new cell(row,col+1);
cells[2] = new cell(row+1,col);
cells[3] = new cell(row+1,col+1);
}
}
- 运行结果
1,0
1,1
1,2
2,1
- - - - - - - - - -
* * * - - - - - - -
- * - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
5,5
5,6
6,5
6,6
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - * * - - -
- - - - - * * - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
Process finished with exit code 0
super() 和 this()
- this(0,0) 是调用本类的构造方法
- super 自己不写默认添加,调用父类的构造方法,默认调用父类的无参构造
class T extends Tetorminor {
T(){this(0,0); } // 调用本类构造
T(int col,int row){
super(); //自己不写默认添加
cells = new cell[4];
cells[0] = new cell(row,col);
cells[1] = new cell(row,col+1);
cells[2] = new cell(row,col+2);
cells[3] = new cell(row+1,col+1);
}
}
- 先调用父类的构造函数,再调用子类的构造函数
举例:
public class SuperDemo {
public static void main(String[] args) {
Boo bb = new Boo();
}
}
class Aoo {
Aoo(){
System.out.println("父类构造");
}
}
class Boo extends Aoo{
Boo(){
System.out.println("子类构造");
}
}
运行结果:
父类构造
子类构造
- super 一定会调用,且要保持和父类的参数一致
- super一定要放在第一句话
public class SuperDemo {
public static void main(String[] args) {
Boo bb = new Boo();
}
}
class Aoo {
Aoo(int a){
System.out.println("父类构造");
}
}
class Boo extends Aoo{
Boo(){
super(5); //必须位于子类构造的第一句
System.out.println("子类构造");
}
}
继承中的构造方法
小结
- 继承:作用:避免代码的重复
- 通过extends关键字实现继承,子类继承父类后 将具有本类的成员以及父类的成员。
- java 中一个类只能继承一个父类,但一个父类可以有多个子类
- java规定构造子类之前必须先构造父类 ,若自己不写super 则在子类构造中默认添加 super(); 来调用父类无参构造。注意super() 必须位于子类构造的第一句。
向上造型
- 举例
public class UpTest {
public static void main(String[] args) {
// 能点出来什么,看类型
Moo o = new Noo(); //向上造型
o.m =5;
o.say();
o.n = 5; // error
o.show =5; //error
}
}
class Moo{
int m;
void say(){}
}
class Noo extends Moo{
int n;
void show(){}
}
父类类型的引用指向子类类型的对象
- 能点出来什么,看类型
小结
- 向上造型:父类类型的引用 指向子类型的对象
- 能点出来什么看类型,和对象无关
- 向上造型的意义: 让子类共用一种父类类型
用法举例(参数例子):
package com.lagu.homwork2.com.danei.review.task3;
public class TetorminorTest {
public static void main(String[] args) {
Tetorminor t = new T(0,0); //先造型再传值
printCell(t);
Tetorminor o = new O(5,5); //先造型再传值
printCell(o);
T t1 = new T(4,3);
printCell(t1); // 传值的同时造型
// Tetorminor t = new T
}
public static void printCell(Tetorminor t){ // Tetorminor t = new T(); 或者 Tetorminor t = new O(); //面向对象的思想传的是对象而不是数据
for (int i=0;i<20;i++){
for(int j=0;j<10;j++){
boolean flag = true; //默认打 -
for(int k=0;k<4;k++) {
if (i == t.cells[k].row && j == t.cells[k].col) { //t.cells[] 是对象的数据。而这个数据又是一个对象
flag = false;
System.out.print("* ");
break;
}
}
if(flag){
System.out.print("- ");
}
}
System.out.println();
}
}
}
class Tetorminor {
cell[] cells;
Tetorminor(){
cells = new cell[4];
}
void drop() {
for (int i = 0; i < cells.length; i++) {
cells[i].row++;
}
}
void moveLeft() {
for (int i = 0; i < cells.length; i++) {
cells[i].col--;
}
}
void moveRight() {
for (int i = 0; i < cells.length; i++) {
cells[i].row++;
}
}
void print() {
for (int i = 0; i < cells.length; i++) {
System.out.println(cells[i].printInfo());
}
}
}
class T extends Tetorminor {
T(){this(0,0); }
T(int col,int row){
super();
cells = new cell[4];
cells[0] = new cell(row,col);
cells[1] = new cell(row,col+1);
cells[2] = new cell(row,col+2);
cells[3] = new cell(row+1,col+1);
}
}
class O extends Tetorminor{
O(){this(0,0);}
O(int col,int row){
cells = new cell[4];
cells[0] = new cell(row,col);
cells[1] = new cell(row,col+1);
cells[2] = new cell(row+1,col);
cells[3] = new cell(row+1,col+1);
}
}
运行结果:
* * * - - - - - - -
- * - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - * * - - -
- - - - - * * - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - * * * - - -
- - - - - * - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
Process finished with exit code 0
返回值的例子:
重写
概念
- 发生在两个类中,并且是子父的关系,子类方法和父类方法签名相同,子类重写了父类方法
- 当方法被重写时时,掉那个看对象
- 如果在子类重写的方法中父类的方法使用super.show()方法
- 重写(override)和重载(overload)的区别
重写:在一个类中,方法名相同,参数列表不同
重载:在两个类中,并且是子类和父类的关系,签名相同。
- 重载:编译时------ .java 到 .class的过程
- 重载时候看类型(看 obj的类型)
内存没东西—只看语法对不对 - 重写:运行时------ jvm加载.class 并运行.class的过程
- 重写看对象
内存才有东西
import com.sun.security.jgss.GSSUtil;
import java.security.spec.RSAOtherPrimeInfo;
public class CxCz {
public static void main(String[] args) {
Ao1 ao1 = new Bo1();
Coo coo = new Coo();
coo.t(ao1);
}
}
class Coo {
void t(Ao1 o){
System.out.println("333");
o.show();
}
void t(Bo1 o){
System.out.println("444");
o.show();
}
}
class Ao1 {
void show(){
System.out.println("111");
}
}
class Bo1 extends Ao1 {
void show(){
System.out.println("222");
}
}
333
222
Process finished with exit code 0
小结
- 重写: 发生在两个类中,并且是子父类的关系,子类方法和父类方法的签名一样
- 重写时可以通过super来访问父类的方法
- 重载为编译期绑定,看类型。重写为运行期绑定,看对象
package,import
-
package 解决类的命名冲突问题
-
格式:package 包名1.包名2…包名n;
-
使用import 对类全称进行声明
-
import java.util.Scanner;
-
import java.util.Arrays;
-
import java.util.Random;
-
import java.util.*;----不建议
-
同一个包里的类不需要使用import
小结
- package 用于避免类的命名冲突,java建议每个类写包名。类的全局限定名 ------------包名 + 类名
- import 用于声明类,或者叫引入类。 访问不同包中类时,需要import
访问修饰符public、private
封装的意义
- 把数据包装起来,保护数据
- 当内部细节改变,只要保证对外定义的功能不变,其它模块就不会受牵连
private和public
- private 修饰的成员遍历和方法只能在本类中调用
- public 修饰的可以在任何地方调用
protected 和默认访问控制
- 默认只能被同包访问
- protected 可以被同包类和子类访问
- 类的修饰词 只能是public 或者 默认
小结
- 访问修饰符 :public 共有的任何类都可以访问
- protected 受保护的 :本类子类同包类可以访问
- 默认 ,什么也不写 ,本类同包类
- private :私有的,只能本类访问
- 类只能用 public 或默认的
- 类的成员如上四种都可以
- 修饰局部变量没有意义
static,final
- 建议和main 平行的方法 加上 static
static 修饰成员变量
- static 修饰的变量不属于对象,属于类 通过 类名.来访问
- static 修饰的的在方法区中
class Aoo {
int a; //属于对象
static int b; //属于类型 在方法区中
void show(){}
}
static 修饰的变量只有一份
而且被共享
举例:
public class Static {
public static void main(String[] args) {
Aoo a1 = new Aoo();
a1.show(); //1,1
Aoo a2 = new Aoo();
a2.show(); //1 ,2
}
}
class Aoo {
int a; //属于对象
static int b; //属于类型
Aoo(){
a++;
b++;
}
void show(){
System.out.println(a);
System.out.println(b);
}
}
结果:
1
1
1
2
Process finished with exit code 0
成员变量:
1)实例变量------------不用static修饰的
2)静态变量------------static变量
何时用静态变量,何时用实例变量
当所有对象共用这个变量,使用静态变量
- 可以 通过 类名. 访问(建议) 且不需要new 对象 和对象没有关系
public class Static {
public static void main(String[] args) {
// Aoo a1 = new Aoo();
// a1.show(); //1,1
// System.out.println(a1.b);
System.out.println(Aoo.b); //建议通过类名. 访问
// Aoo a2 = new Aoo();
// a2.show(); //1 ,2
}
}
class Aoo {
int a; //属于对象
static int b; //属于类型
Aoo(){
a++;
b++;
}
void show(){
System.out.println(a);
System.out.println(b);
}
}
static修饰方法
-
方法加不加 static的区别: static 修饰的方法是没 this.的
-
Static 只需要对参数有关
小结
-
非静态方法:----有隐式this
可以直接访问静态变量和实例变量
需要访问实例变量 -
静态方法:----没有隐式this
只能直接访问静态变量,不能直接访问实例变量 -
何时用静态方法,何时用非静态方法:
不需要访问实例变量时即可使用
static块
举例:
public class Static {
public static void main(String[] args) {
Coo c1 = new Coo(); // 111
Coo c2 = new Coo(); // 111
}
}
class Coo{ //static 块
Coo(){
System.out.println("111");
}
static { //加载类的时候被执行 ,只执行一次 ,因为类只被加载一次
System.out.println("静态代码块");
}
}
结果:
静态代码块
111
111
Process finished with exit code 0
何时使用静态代码块
- 一般用于加载静态资源(图片、音频、视频)
小结
- static修饰成员变量 :属于类 ,不属于对象,存在方法区中,只有一份。为所有对象公有的数据,常常通过类名来访问 。何时用:某个数据被所有对象共享公有
- static修饰方法:没有隐式this 传递,不能直接访问实例变量。 何时用:方法的执行只于参数相关,与对象无关。常常通过类名直接访问
- static 块:属于类的块,在类加载期间执行,并且只执行一次。 何时用:常用于加载静态资源(图片,音频,视频)
final关键字
final修饰变量
- 意味着不可变
- 修饰的成员变量,只能在声明或构造函数中初始化
举例
class Doo{ //final修饰变量
final int a = 5; //声明同时初始化
final int b;
Doo(){
b = 5; //先声明,再在构造中初始化
}
void show(){
final int c; //一般都不用
// System.out.println(c); 错误 c没有(值)初始化
c = 5;
System.out.println(c);
}
void say(){
//a = 88; // 错误,final 修饰的错不能改变
}
}
final修饰方法
举例:
class Eoo{ //finl修饰的方法--不可被重写
void show(){ }
final void say(){ }
}
class Foo extends Eoo{
@Override
void show(){
}
// void say(){} //错误,final方法不能被重写
}
举例:
- 修饰的类不被继承
final修饰类
举例:
class Ioo{}
final class Goo extends Ioo{ //可以继承别的类
}
//class Hoo extends Goo{} //错误,final 修饰的类不能被继承
小结
- final修饰变量,只能在声明和构造函数时初始化,变量不能被修改 。
- final修饰方法,不可被重写
- final 修饰类不可被继承
static final
- 声明同时必须初始化
public class StaticFinal {
public static void main(String[] args) {
//编译时,直接将Aoo.PI 替换成3.1415926
System.out.println(Aoo.PI);
// 在方法区中加载Aoo.class
// 以及static 成员,以及方法
System.out.println(Aoo.num);
}
}
class Aoo{
//声明常量,必须声明的同时初始化
//建议所有字母大写
static final double PI = 3.1415926;
static int num = 5;
}
小总结
抽象类、抽象方法
- 不知道方法体(有多种情况)怎么写,通过子类来写,java不建议空方法,把它写成抽象方法(不完整)
- 计算相同周长不同形状的面积
- 抽象方法:由abstract修饰
只有方法的定义,没有方法体的 - 抽象类:由abstract修饰
可以包含抽象方法,也可以包含普通方法 - 包含抽象方法的的类,必须是抽象类。类中没有抽象方法,也可以将类声明为抽象类
- 抽象类不能被实例化
shape s = new shape(); //错误 - 一般需要被继承:
1)子类也声明为抽象类
2)子类重写抽象方法 ----首选 - 抽象类的意义:
1)封装子类公有的成员
并为子类提供公共的类型
2)定义抽象方法,由子类来做不同的实现,但是入口(方法名)是一样的
抽象继承类
抽象类的意义
- 抽象类也是父类,意义在于避免重复的代码
举例:根据周长计算不同图形的面积
class ShapeDome{
public static void main(String[] args) {
//Shape shape = new Shape(); 抽象类不能new 对象
Shape[] shape = new Shape[2];
shape[0] = new Yuan(1);
shape[1] = new Zhen(1);
max(shape);
}
public static void max(Shape[] shape){
double max = shape[0].area();
int maxIndex = 0;
for(int i=0;i<shape.length;i++){
double area = shape[i].area();
if(area > max){
max = area; //重置max的值
maxIndex = i; //重置最大面积索引
}
}
System.out.println("最大面积:" + max + " 下标是" +maxIndex);
}
}
abstract public class Shape {
double c;
abstract double area();
}
class Yuan extends Shape{
Yuan(double c){
this.c = c;
}
@Override
double area(){
return 0.796*c*c;
}
}
class Zhen extends Shape{
Zhen(double c){
this.c = c;
}
@Override
double area(){
return 0.625*c*c;
}
}
运行结果
最大面积:0.796 下标是0
小结
- 抽象方法:由abstract修饰
只有方法的定义,没有方法体的 - 抽象类:由abstract修饰
可以包含抽象方法,也可以包含普通方法 - 包含抽象方法的的类,必须是抽象类。类中没有抽象方法,也可以将类声明为抽象类
- 抽象类不能被实例化
shape s = new shape(); //错误 - 一般需要被继承:
1)子类也声明为抽象类
2)子类重写抽象方法 ----首选 - 抽象类的意义:
1)封装子类公有的成员
并为子类提供公共的类型
接口
- 接口是一个标准,一个规范,只有满足这个标准才能干某件事。
- interface 接口名
- 接口里只能包含常量和抽象方法
- 接口是抽象的,完全不完整的,不能实例化不能new对象,是制订标准让其它类来实现的
- 实现接口通过 implements 关键字(实现-遵守标准),而且需要将接口的所有抽象类都实现
- 一个类可以实现多个接口,用“,”间隔 ,且子类的实现的重写方法的修饰权限必须大于或等于父类的权限
- 一个类又想继承父类,又想实现接口,必须先继承后实现
- 接口与接口时间是继承关系
举例:
public interface JieKou {
public static final int NUM = 5; //public static final 可以省略
int B = 5;
public abstract void show();
void say();//默认 Public abstract
}
interface JieKou2{
void sayHi();
}
class Coo implements JieKou{ //遵守标准
@Override
public void show(){
System.out.println("111");
}
@Override
public void say(){
System.out.println("222");
}
}
class Doo implements JieKou,JieKou2{
@Override
public void show(){
System.out.println("333");
}
@Override
public void say(){
System.out.println("444");
}
public void sayHi(){
System.out.println("555");
}
}
class Foo extends Coo implements JieKou,JieKou2{
public void sayHi(){
}
}
interface JieKou3 extends JieKou{ //接口之间使用继承
void sayHello();
}
class Eoo implements JieKou3{ //要重写三个方法
public void sayHello(){}
public void show(){}
public void say(){}
}
定义一个接口
实现接口
- 接口 可以 . 出来 runner 接口内的东西,子类内地东西 . 不出来
- . 看类型,jiekou 只能. 出来JieKou的内容
- 重写看对象,继承看类型
class test{
public static void main(String[] args) {
JieKou jieKou = new Goo();
jieKou.say(); //子类的
jieKou.show(); //子了的
//jieKou.show1();
}
}
public interface JieKou {
public static final int NUM = 5; //public static final 可以省略
int B = 5;
public abstract void show();
void say();//默认 Public abstract
}
class Goo implements JieKou{
void show1(){}
public void say(){}
public void show(){}
}
接口继承
练习:
class test{
public static void main(String[] args) {
JieKou jieKou = new Goo();
jieKou.say();
jieKou.show();
System.out.println(JieKou.B);
//jieKou.show1();
}
}
public interface JieKou {
public static final int NUM = 5; //public static final 可以省略
int B = 5;
public abstract void show();
void say();//默认 Public abstract
}
class Goo implements JieKou{
void show1(){}
public void say(){}
public void show(){}
}
interface JieKou2{
void sayHi();
}
class Coo implements JieKou{ //遵守标准
@Override
public void show(){
System.out.println("111");
}
@Override
public void say(){
System.out.println("222");
}
}
class Doo implements JieKou,JieKou2{
@Override
public void show(){
System.out.println("333");
}
@Override
public void say(){
System.out.println("444");
}
public void sayHi(){
System.out.println("555");
}
}
class Foo extends Coo implements JieKou,JieKou2{
public void sayHi(){
}
}
interface JieKou3 extends JieKou{ //接口之间使用继承
void sayHello();
}
class Eoo implements JieKou3{ //要重写三个方法
public void sayHello(){}
public void show(){}
public void say(){}
}
接口和抽象类的区别
- 抽象类是共有的本质是还是父类,
- 接口是特别的,不是公有的,只有遵守才能干某事
实现类
. 什么看类型
多态
- 多种形态
- 特点1:一个类型的引用指向不同的对象时会有不同的功能
- 同一个对象,造型成不同的类型时,会有不同的功能(方法)
向上造型
强制类型转换
- 编译器认为子类大,父类小
- 强转看对象
instanceof 关键字
小结
- 同一类型的引用指向不同的对象时 有不同的意义
- 同一个对象造型为不同的类型时有不同的功能
- 强转:父到子 前提:对象是子 ;转为接口 前提:对象实现了该接口
- 强转失败冒异常:通过instanceof来解决
语法:
引用 instanceof 数据类型 --------------boolean
强转成功与否,看对象
举例:
public class DuoTai {
public static void main(String[] args) {
/*
* 向上造型
*/
/* JieKou jieKou = new Boo(); //向上造型 是实现类
Aoo aoo = new Boo();//向上造型 是子类
aoo.b();// . 看类型
// JieKou o3 = new Coo(); 错误,类型不匹配 既不是子类 又不是实现类*/
/**
* 向上造型时,点出来什么,看类型
*/
/*Aoo aoo1 = new Boo();//向上造型 是子类
aoo1.b();// . 看类型
//aoo1.num1 =5;//编译错误 ,点出来什么看类*/
//强转看对象
Aoo o1 = new Boo();//向上造型
Boo o2 = (Boo) o1;//正确 ,o1指向的对象是Boo所以成功
JieKou o3 = (JieKou) o1; //正确
// o1 指向的对象实现了JieKou
// Coo o4 = (Coo) o1; //运行报错 ClassCastException 类型转换异常
// o1 指向的对象与Coo无关
// instanceof 为true两种情况
//1.对象为该类型
//2.对象实现了该接口
if (o1 instanceof Coo){ // false
Coo o4 = (Coo) o1;
}
}
}
interface JieKou{
void a();
}
abstract class Aoo{
abstract void b();
}
class Boo extends Aoo implements JieKou{
int num1;
void b(){}
public void a(){}
}
class Coo extends Aoo{
int num2;
void c(){}
void b(){}
}
class Doo extends Boo{}
练习:
public class LianXi {
public static void main(String[] args) {
Abs abs = new Eoo();
abs.b();
Eoo eoo = (Eoo) abs; //abs的对象为Eoo类型
eoo.num =5;
eoo.a();
Inter inter = (Inter) abs; //abs的对象 实现了 Inter接口
// Foo foo = (Foo)abs;// abs的对象不是Foo类型
if(abs instanceof Foo){
Foo foo1 = (Foo)abs;
}
}
}
interface Inter {
void a();
}
abstract class Abs {
abstract void b();
}
class Eoo extends Abs implements Inter{
int num;
void b(){}
public void a(){}
}
class Foo extends Abs {
int num2;
void b(){}
}
应用:
改动:
内部类
- 类里面套类
- 一个类只能被另外一个类使用,对外不可见
- 内部类对象只能在外部类中被创建
内部类可以直接访问外部类所有成员(包括私有的)
定义成员内部类
##内部类创造对象
匿名内部类
- 定义匿名内部类条件:1.只创建一个对象 2. 是子类或者某个接口的实现类
举例:
public interface NiMing {
}
interface NiMing2{
void show();
}
class test{
public static void main(String[] args) {
//创建是实现类对象 名为niMing
NiMing niMing = new NiMing() {int a;};
//创建实现类对象 名为niMing2
NiMing2 niMing2 = new NiMing2() {
@Override //实现类的成员
public void show() { System.out.println("qwer"); }
};
niMing2.show();
}
}
总结
- 面向对象三大特征
封装:3个层次:类本身就是一种封装,在封装数据、方法 ,把类当成一个整体。方法也是一种封装功能,还要通过访问修饰符来封装。分别实现 :类做为一个整体性强 隐藏实现的细节 保证数据的安全
继承:避免代码重复,使用extends关键字
多态:既多种形态,在继承之上 。
两种实现方法: 一个类型指向不同对象,有不同的实现(一个抽象类的一个方法。被多个子类重写)
同一个对象造型成不同的类型,有不同的功能(一个实现类 实现多个接口)
提高可维护性、可扩展性