面向过程编程
面向对象编程
本质:以类的方式组织代码,以对象的形式组织数据
特征:封装、继承、多态
二、类和对象的关系
类:抽象的数据类型,是对事物整体的描述,并不能代表某一个具体的事物
对象:是抽象概念的具体实例(人-->张三,狗-->旺财)
创建与初始化对象
使用new关键字创建对象,除了分配内存空间以外,还会给创建好的对象进行默认的初始化以及对类中构造器(构造方法)的调用,new关键字本质就是在调用构造器
类名 对象名//创建对象
对象名=new 类名(); //实例化对象
类名 对项名 =new 类名();//二合一
同一个包内可以直接调用
练习 创建一个person类,属性为name,age,gander
public class Person{
string name;
int age;
char gender;
}
public class Test{
Person per1=new Person();
Person per2=new Person();
Person per3=new Person();
per1.name="张三";
per2.age=20;
per3.gender="男";
sysout(pri1.name);
}
成员变量
实例变量:变量是属于对象的
声明实例变量
[修饰符] 数据类型 变量名=[值]
如果在声明的时候赋值了,就相当于在实例化对象的时候,该成员变量的默认值,后期可改
int id;
String name="张三";
使用实例变量
前提:必须得有对象
访问方式:对象名.成员变量名;
成员变量是有初始值的(默认值)
成员变量和局部变量的区别
1.位置:成员变量在类里;局部变量在某个局部(方法里,循环里)
2.作用范围:本类及其他类可以调用(符合访问修饰符);局部变量当前方法作用域
3.初始化值:成员变量有初始化值;局部变量没有初始化值
4.内存中的位置:成员变量在堆中;局部变量在栈中
5.生命周期:成员变量是在对象被回收的时候销毁;局部变量是当大括号运行完毕就销毁。
成员变量的类型可以是任意类型(可以基本数据类型,可以是引用数据类型(String,数组,自定义类))
练习 创建一个Employee类,内有属性(id/name/salary/phone);创建Employee对象,为对象所有的属性赋值,并展示该员工所有信息
public class Employee{
int id;
String name;
double salary;
Phone phone;//引用数据类型,自定义的类
}
public class Phone{
String name;
String brand;
int size;
}
Public class Test{
public static void mian(String [] args){
Employee emp= new Employee();
emp.id=11;
emp.name="张三";
emp.salary=123;
Phone phone=new Phone ();
phone.name="P30pro"
phone.brand="华为";//员工手机的品牌;phone.brand是手机的品牌
emp.phone=phone;//将phone这部手机设置是emp的,不然就空指针异常了
sysout(emp.name+"的手机品牌是"+emp.phone.brand);
}
}
类变量:变量属于类(待补充)
成员方法
1.先声明后使用(在本类内可以直接调用,在本类以外需要先创建对象才能调用)
2.调用一次执行一次,不调用不执行,调用一次压入一次方法栈
分类:实例方法(属于对象的,必须有对象才可以)、类方法(待补充)
语法:[修饰符] 返回值类型 方法名([形式参数]){方法体}
实例方法分类:无参无返回值、有参无返回值(可以是任意类型,基本数据类型,引用数据类型)、无参有返回值(返回值类型任意,但要指定只能指定一个;只能有一个返回值,有返回值的方法必须要执行到return)、有参有返回值
如果要是有返回值的,方法里一定要检测到有返回值的才能结束。
//面向过程,//打印5次好好学习天天向上
public class Test{
public static void main (String [] args){
for(int i=0;i<5;i++){
sysout("好好学习,天天向上");
}
}}
//面向对象,//无参无返回值 //打印5次好好学习天天向上
public class Test{
public static void main (String [] args){
MyUtil myUtil =new MyUtil();
myUtil.print();
}}
//创建一个人去做这件事,创建MyUtil类,里面写print方法,以后就可以重复使用了
public class MyUtil{
public void print(){ //无参无返回值
for(int i=0;i<5;i++){
sysout("好好学习,天天向上");
}
}
}
//有参无返回值,创建n行直角三角形
public class Test{
public static void main (String [] args){
MyUtil myUtil =new MyUtil();
myUtil.printNum(5);//需要传参
}}
public class MyUtil{
public void printNum( int num){//执行的时候一定有值
for(int i=0 ;i<num;i++){
for (int j=0;j<=i;j++){
sysout("*");
}
}
}
}
//有参无返回值练习 //遍历int数组 ,并把数组从小到大排序
public class Test{
public static void main (String [] args){
int [] arr= new int{3,4,8,5,7,8};
MyUtil myUtil =new MyUtil();
myUtil.printNum(arr);//需要传参//遍历int数组
myUtil.sort(arr);//从小到大排序(冒泡)
}}
public class MyUtil{
public void printNum( int [] arrs){//执行的时候一定有值
for(int i=0 ;i<arrs.length;i++){ //遍历int数组
sysout(arrs[i]);
}}
public void sort(int [] arrs){
//从小到大排序(冒泡)
for(int i=0;i<arrs.length;i++){
for(int j=0;j<arrs.length-i-1;j++){
if(arrs[j]>arrs[j+1]){
int temp=arrs[j];
arrs[j]=arrs[j+1];
arrs[j+1]=temp;
}
}
}
}
}
//无参有返回值
//[public] 返回值类型 方法名(){}
//随机产生一个四位数字
public class Test{
public static void main (String [] args){
MyUtil myUtil =new MyUtil();
int a=myUtil.randomNum();//把myUtil.randomNum()的返回值赋给同类型的变量
sysout(a);
}}
public class MyUtil{
public int randomNum( ){
int num =(int)(math.random()*9000+1000);
return num; //返回int型num。如果想返回多个值,类型相同的可用数组;不同的话可以使用集合(后面写)。有返回值的方法必须要执行到return。
}
}
练习随机返回n个随机数
public class MyUtil{
public int random5Num( ){
int [] arrs=new int[3];
for(int i=0;i<3;i++){
arrs[i]=(int)(math.random()*9000+1000);
}
return arrs; //返回数组。
}
}
public class Test{
public static void main (String [] args){
MyUtil myUtil =new MyUtil();
int []a=myUtil.random5Num();
sysout(a);
}}
//有参有返回值 随机返回n个
public class MyUtil{
public int randomnNum( ){
int [] arrs=new int[n];
for(int i=0;i<n;i++){
arrs[i]=(int)(math.random()*9000+1000);
}
return arrs; //返回数组。
}
}
public class Test{
public static void main (String [] args){
MyUtil myUtil =new MyUtil();
int count=7;
int []a=myUtil.randomnNum(count);//有参
for(int i=0;i<a.length;i++){
sysout(a);//有返回值
}
}}
练习
public class test{
public static void main (String [] args){
MyTools myTools =new MyTools();
double max3 =myTools.max3(23.5,60,7);
double max1 =myTools.max1(20,7);
}
}
public class MyTools{
public double max1(double a,double b){
return a>b? a:b;
}
public double max3(double a,double b,double c){
double max=max1(a,b); //调用类内方法可以直接调用不需要创建对象
return max>c?max:c;
}
}
方法入栈:先进后出
方法调用用一次执行一次,调用一次就入栈一次
入栈:在栈内存中分配一块空间供当前这个方法运行使用,方法结束就销毁出栈,再调用时再入栈。
方法重载
解决相同类型方法,起名问题
同一类中方法名可以相同,但是形参列表必须不同(顺序/个数/类型)
和返回值无关,和修饰符也无关
参数传递机制
引用数据类型:栈内存存储的是地址,在方法传参的时候,就是地址传递(引用)--。多个变量指向同一个空间(堆内存,常量池)
基本数据类型:栈内存中存储的是值,在方法传参的时候,就是值传递
递归
直接递归:方法自己调用自己(容易内存溢出)、间接递归:a->b->c->a
public class test {
public static void main(String [] args){
Function b= new Function();
b.function(0);
}
}
public class Function{
public void funcion(int a){
if (a<3){
sysout("好好学习天天向上");
a++;
function(a);
}
}
}
/**
构造方法:创建对象时候必须要调用的,一个类什么都不写也会存在一个无参构造方法。
- 与类名相同
- 必须没有返回值,也不是void
作用:
- new本质就是在调用构造器
- 初始化对象的值
注意:
- 如果定义了有参构造方法,无参构造必须显式定义
- 快捷键Alt+Insert(IDEA)
public class Person{
String name;
//一旦有有参构造方法,无参构造必须显式定义
public Person(){//无参构造
}
public Person(String name){//有参构造
this.name=name;//this.name 是类里的变量,name是传进来的参数
}
}
引用类型
对象是通过引用来调用的,栈---->堆
**/
三、三大特性
封装
该露的露,该藏的藏,高内聚(类内部数据操作细节自己完成,不许外部干涉)低耦合(尽量暴露少量的方法给外部使用),通过接口方法来操作
属性私有,get/set方法、可设置元素:类,成员变量,成员方法
权限(访问)修饰符:public、缺省的、protected、private
范围:
本类内 | 本包内 | 其他包的子类 | 其他包的非子类 | |
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
缺省的 | √ | √ | × | × |
private | √ | × | × | × |
作用:提高安全性,隐藏代码实现细节,统一接口,系统的可维护性
...
public int getId(){//public方法
}
public void setId(int id){
this.id=id;
}
class Demo1{//缺省的类
}
protected class Demo2{//protected类
}
public void test(){
private int a;//private成员变量
}
...
练习
//创建一个employee类,工友属性id age name salary,对所有属性进行私有化,每个属性都要提供对应的get/set方法,并且提供setAll和getInfo
//创建共三个对象,存放在对象数组中,循环遍历其个人信息
public class Employee {
private int id;
private int age;
private String name;
private double salary;
//set方法
public void setId(int a){
id =a;
}
public void setAge(int b){
age =b;
}
public void setName(String c){
name =c;
}
public void setAll(int a,int b,String c,double d){
id=a;
age =b;
name =c;
salary=d;
}
//get方法
public int getId(){
return id;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String getInfo(){
return id+"\t"+name+"\t"+age+"\t"+salary;
}
}
public class Test{
public static void main(String [] args){
Employee [] employees =new Employee[3];//创建一个对象,放长度为三的数组
employees [0]=new Employee();//创建这个数组的第一行
employees [0].setId(11111);
employees [0].setAge(12);
employees [0].setName("刘欢");
employees [1]=new Employee();
employees [1].setId(11112);
employees [1].setAge(25);
employees [1].setName("法外狂徒");
employees [2]=new Employee();
employees [2]. setAll(11113,57,"老王",3355.3);
for(int i=0;i<employees.length;i++){
sysout(employees.getInfo());
}
}
}
练习
//基于文本界面的用户登录注册
public class Test{
public static void main(String []args){
java.util.Scanner input=new java.util.Scanner(System.in);
int num =input.nextInt();
int count=0;//记录用户个数
User [] users=new User[5];//保存用户的数组
if(num==1){
sysout("欢迎来到注册页面\n请输入用户名和密码");
int username=input.nextInt();
int password=input.nextInt();
sysout("请输入您的真实姓名:");
String name=input.next();
//用户信息的保存(对象数组)将注册用户信息,封装到对象内,将对象存在数组中
//1.判断容量是否充足
if(count==users.length){
//需要扩充
User[] newUser=new User[user.length*2];
for(int i=0;i<users.lenth;i++){
newUser[i]=users[i];
}
users=newUser;
}
//2.保存用户
User.user=new User();//把用户数据封装成用户对象,再把用户对象放到数组里
user.setId(count);
user.setUsername(username);
user.setPassword(password);
user.setName(name);
users[count++]=user;//把用户对象放到数组里
}else if(num==2){
sysout("欢迎来到登录页面\n请输入用户名和密码");
int username=input.nextInt();
int password=input.nextInt();
//登录检查
for(int i=0;i<count;i++){
if(username==users[i].getUsername()&&password==users[i].getPassword){
//找到登录人
user=users[i];
break;
if(){user==null;
sysout("用户名密码错误");
}
}
}
}else if(num==3){
sysout("确认退出吗?0/1");
int flg=input.nextInt();
if(flg==0){
break;
}
}
}
}
//user类
public class User(){
private int id;
private int username;
private int password;
private String name;
public void setId(int i){
id =i;
}
public int getId(){
return id;
}
public void setUsername(int u){
username =u;
}
public int getUsername(){
return username;
}
public void setPassword(int p){
password=p;
}
public int getPassword(){
return password;
}
public void setName(int n){
name=n;
}
public int getName(){
return name;
}
}
构造器
是类的五大成员之第三大成员
成员变量、成员方法、构造器、初始化块、内部类
构建对象的(实例化对象的)又称为构造方法(和方法类似)
2.构造器语法
方法:修饰符 返回值类型 方法名(形参列表){代码块}
构造器:没有返回值(void也没有)、方法名必须和类名一致、创建对象时候必须要调用的,一个类什么都不写也会存在一个无参构造方法,如果写了就会覆盖。
public class Person{
public person(){//没有返回值(void也没有)、方法名必须和类名一致
sysout("无参构造");
}
}
public class Test{
public static void main (String [] args){
Person person =new Person();
}
}
//构造器也可以重载
public class Person{
public person(){//没有返回值(void也没有)、方法名必须和类名一致
sysout("无参构造");
public person(String n){//有参构造器、构造器可以重载、但如果写了就会覆盖默认构造器
sysout("有参构造");
}
}
public class Test{
public static void main (String [] args){
Person person =new Person();
}
}
3.构造器的执行时机
在实例化对象的时候调用,实例化一次调用一次
构造器只能在new的时候调用,后续对象名打点调用不了
4.构造器和set方法
有参构造器:在实例化对象的时候就已经知道属性的时候使用
set:单个属性值的修改
5.封装类必备三要素:1私有属性、2公有get/set方法、3共有的无参构造器
一般情况:1私有属性、2公有get/set方法、3全参构造器(所有属性值的初始化)、4显示的创建无参构造器、5getInfo()方法--->toString
public class Student{
private int id;//1私有属性
private String name;//1私有属性
public Student(int i,String n){//3全参构造器(所有属性值的初始化)
id =i;
name=n;
}
public Student(){//4显示的创建无参构造器
}
public int setId(int i){//2公有set方法
id=i;
}
public int getId(){//2公有get方法
return id;
}
public String setName(String name){//2公有set方法
this.name=name;
}
public String getName(){//2公有get方法
return name;
}
public String getInfo(){//5getInfo()方法--->toString
return id+"\t"+name;//\t”为“转义字符“,代表的是一个tab,也就是8个空格
}
}
Java中无参构造器的作用是什么?(就像你给的代码中的Student默认构造函数,可以在里面执行一些默认的代码或操作。这样用户在初始化这个类时,可以默认执行一些操作。比如环境准备,默认数据填充等。这样用户拿到类的对象时,就已经有一些默认数据了。)
/**声明一个员工类,包含属性:编号、姓名、薪资、性别,要求属性私有化
提供无参构造器和有参构造器
提供getInfo方法**/
public class Employee{
//属性私有化
private int id;
private String name;
private double salary;
private char gender;
//提供无参构造器
public employee(){
}
//提供有参构造器
public employee(int i,String n,double sa,char g){
id=i;
name=n;
salary=sa;
gender=g;
}
//get、set方法
public void setId(int i){
id=i;
}
public int getId(){
return id;
}
//......
//提供getInfo方法
public String getInfo(){
ruturn id+"\t"+name+"\t"+salary+"\t"+gender;
}
}
//测试类
public class Test{
public static void main(String [] args){
// Employee[] employee =new Employee[3];
// employee[0]=new Employee();
// employee[0].id=11111;
// employee[0].name="张三丰";
Employee employee =new Employee();
//使用无参构造器,用set方法设置值
employee.setId(11111);
employee.setName("张三丰");
//......
sysout(employee.getInfo());
//使用有参构造器,在new的时候直接给初始化值
Employee employee2 =new Employee(11112,"张无忌",500,'男');
sysout(employee2.getInfo());
}
}
this关键字:当前对象(不是当前类)
作用1:this.内容(属性、方法)
可以用在所有方法(包括构造器)
public class Car{
private int id=20;//这是个成员变量,在创建对象的时候就初始化值了
private String name;
//get、set方法
public void setId(){
id=10;//这是个局部变量。//同一个作用域内不允许重名的变量,但是成员变量和局部变量重名
sysout(id);//这时候运行的的结果id=10,因为有局部变量的时候默认访问局部变量
sysout(this.id)//要是想访问成员变量id,就用this.属性名,this是当前对象,谁调的setId就是谁这里是car调的
}
}
//测试类
public class Test{
public static void main(String [] args){
Car car =new Car;
car.setId();
}
}
同一个作用域内不允许重名的变量,但是成员变量和局部变量重名
局部变量和成员变量重名的情况下,候默认访问局部变量
要是想访问成员变量id,就用this.属性名,this是当前对象,谁调的setId就是谁,这里是car调的
作用2:应用在构造器、调用本类的其他构造器
注意:this()必须在构造器的首行
public class Car{
private int id=20;//这是个成员变量,在创建对象的时候就初始化值了
private String name;
//get、set方法
public void setId(){
id=10;//这是个局部变量。//同一个作用域内不允许重名的变量,但是成员变量和局部变量重名
sysout(id);//这时候运行的的结果id=10,因为有局部变量的时候默认访问局部变量
sysout(this.id)//要是想访问成员变量id,就用this.属性名,this是当前对象,谁调的setId就是谁这里是car调的
}
//2个参数的构造器
public Car(int id,String name){
this.id=id;
this.name=name;
}
}
//一个参数的构造器
public Car(String name){
this.name=name;
}
//有多个构造器,可以参数多的在本类中调用参数少的构造器
public Car(int id,String name){
this(name);//调用一个参数的构造器了,this()必须在构造器的首行
this.id=id;
}
//无参构造器
public Car(){}
}
//测试类
public class Test{
public static void main(String [] args){
Car car =new Car;
car.setId();
}
}
Alt + Insert:代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等
标准Javabean(实体类)
类必须是具体的和公共的,并且具有无参数的构造方法,成员变量私有化,并且提供用用来操作成员变量的set和get方法。(其实就是封装类的必备三要素)
包
语法:全小写,用.来分割级别
作用:
1.避免类的冲突(有必要创建两个同名类)、
2.分门别类的管理(Java.lang包含Java的核心类、Java.net、java.io、java.sql、java.util ...)
使用方式:使用其他包下的内容时,要先导包 import java.uli;.Scanner(Java.lang包除外)
使用同包下的内容不需要导包
3.可以控制某些类型成员的可见范围(访问修饰符 缺省的只能访问本包内,其他包访问不了)
static修饰成员变量(静态的)
成员变量:属于对象
类变量:属于类,在成员变量添加修饰符static
👇实例变量例子
public class Test{
public static void main (String [] args){
Phone phone1 =new Phone(1,"华为",5000);//直接调用构造器赋值
Phone phone2 =new Phone(2,"小米",3000)
sysout(phone1.getInfo);
sysout(phone2.getInfo);
}
}
public class Phone{
private int id;
private String name;
private double price;
//get,set方法
public int setId(int id){
this.id=id;
}
//...
//有参构造器
public phone(int id,String name, double price){
this.id=id;
this.name=name;
this.price=price;
}
//无参构造器
public phone(){
}
//getInfo获取信息
public String getInfo(){
return id+\t+name+\t+price
}
}
类的加载时机:
在第一次使用这个类的时候,先加载后使用(在使用main方法之前就先调用了Test类)
类只加载一次,在没有被销毁(垃圾回收)之前都不会再加载(在方法区每个类只有一个加载信息)
👇类变量例子
类变量:在成员变量前加static
private int id;
private String name;
private static double price;//其他代码和上面一样,只改这行//结果
1 华为 3000//空间开辟再方法区内,并且只有一份,所以是共享的
2 小米 3000
类在加载的时候:先加载所有的静态资源、再加载所有普通资源
静态的属性,空间开辟再方法区内,并且只有一份,原因类只加载一次,所有对象操作该属性的时候,操作的都是方法去这一个空间,达到共享的目的。(math.pi派
用法:1.对象.静态属性(符合权限修饰符的范围)
private static double price--->static double price
phone1.price=5000;
2.类名.静态属性(符合权限修饰符的范围)推荐
Phone.price=5000;
static修饰成员方法
实例方法:属于对象
类方法:属于类
public class Test{
public static void main (String [] args){
Phone phone1 =new Phone(1,"华为",5000);//直接调用构造器赋值
Phone phone2 =new Phone(2,"小米",3000)
sysout(phone1.getInfo);
sysout(phone2.getInfo);
}
}
public class Phone{
private int id;
private String name;
private double price;
//get,set方法
public int setId(int id){
this.id=id;
}
//...
//普通方法
public void method(){
sysout("这是一个普通方法");
}
//静态方法
public static void function(){
sysout("静态方法");
}
//有参构造器
public phone(int id,String name, double price){
this.id=id;
this.name=name;
this.price=price;
}
//getInfo获取信息
public String getInfo(){
return id+\t+name+\t+price
}
}
在加载的时候,依然是先加载静态方法,再加载普通方法
使用方法:
1.对象.静态方法();
phone1.funcion();
2.类名.静态方法();推荐,不依赖与对象,工具类的方法设置为static
Phone.funcion();
注意:静态资源内只能直接使用静态资源,不能直接使用非静态资源(因为类加载的时候还没出来),因为静态资源里没有this
非静态资源内部可以直接使用this关键字
static用途:用于属性、为了资源共享;用于方法、为了类名调用方便。
9.静态导入
import static java.lang.Math.PI;
...
sysout(PI)
10.一些工具类介绍
10.1Arrays数组工具类
java.unil.Array:提供了很多静态方法对数组进行操作,而且如下每一个方法都有各种重载形式
copyOf() 数组的拷贝--用于数组扩容
public class Test{
public static void main (){
int[] arrs={3,4,6};
///被代替代码段//
int[] newArrs=new int[arrs.length];
for(int i=0;i<arrs.length;i++){
newArrs[i]=arrs[i];
}
//array工具类方法代替上面代码//
int[] ints = Arrays.copyOf(arrs(被复制的数组名),arrs.length(新数组需要的长度));//有很多种类,因为方法重载
}
}
sort() 数组排序,默认从小到大
public class Test{
public static void main (){
int[] arrs={3,4,6,1,2,5,3,8};
Arrays.sort(arrs);//默认从小到大排序
for(int i=0;i<arrs.length;i++){
sysout(arrs[i]);
}
}
}
toString() 将数组内容拼接成字符串
public class Test{
public static void main (){
String[] strs={"北京","朝阳区","群众"};
sysout(Arrays.toString(strs));
}
}
结果:["北京","朝阳区","群众"]
10.2.系统类system
系统类中有很多好用的方法,常用的两个
static long currentTimeMills();返回当前系统的时间距离1970-1-1 0,0:0的毫秒值
System.exit(status 0);//系统退出
public class Test{
public static void main(String [] args){
sysout(System.currentTimeMills());//返回当前系统的时间距离1970-1-1 0,0:0的毫秒值
System.exit(status 0);//系统退出,一般不用
}
}
static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length);从指定数组中复制一个数组,复制从指定的位置开始,到目标的位置结束。
10.3数学类Math
random() //产生[0-1)随机数
abs(int) //绝对值
ceil(double) //向上取整(比参数大的最近的整数)
floor(double) //向下取整(比参数小的最近的整数)
round(double) //四舍五入
pow(int a,int b) //返回a的b次方
sqrt(double a) //开根号
PI //返回圆周率
max(double a,double b); //返回ab中最大的
min(double a,double b); //返回ab中最小的
public class Test{
public static void main(String [] args){
sysout(Math.abs(-5));//返回绝对值--》5
sysout(Math.ceil(23.1));//向上取整--》24.0
sysout(Math.floor(23.1));//向下取整--》23.0
sysout(Math.pow(2,3));//返回2的3次方--》8
sysout(Math.sqrt(4));//开4平方--》2
}
}
11.API
只要是Java提供的类,在API里都能查到(上面的工具类都能查到,很全)
继承
1.1继承的好处:提高复用性
1.2.语法:class Sub extends Super{}
1.3使用时机:多个类中有相同内容;在写子类时候发现可有父类可继承
是对某一批类的抽象,关键字extends,Java只有单继承
在Java中所有的类都默认直接或间接继承Object类(String是继承于Object类的)
Ctrl+H 继承树快捷键
public class Person(){
... ...
}
public class Student extends Person(){
... ...
}
2.继承之成员变量
父类中所有的成员变量都会被子类继承,但如果父类中的成员变量是私有的,子类继承了但不能直接访问,可通过继承的公有方法进行访问。
//父类中所有的成员变量都会被子类继承,但如果父类中的成员变量是私有的,子类继承了但不能直接访问
/*
*父类Animal
*/
public class Animal{
//属性
public Stirng name="旺财";
int age;
public String color;
//一些普通方法
public void eat(){
sysout(name+"在吃饭");
}
public void run(){
sysout(name+"在奔跑");
}
//方法:get、set、有参构造、无参构造
public String setName(String name){
this.name=name;
}
public String getName(){
return name;
}
//...其他get、set方法...
//有参构造
public Animal(String name,int age,String color){
this.name=name;
this.age=age;
this.color=color;
}
//无参构造
public Animal(){
}
}
/*
*子类Dog继承父类Animal
*/
public class Dog extends Animal{
public Stirng name="二哈";//子类和父类中可以出现相同的属性名称,如果有重名属性默认访问子类属性,如果向访问父类属性要使用关键字super
public void careTaker(){
sysout(name+"在守护家园");//name是this.name,这个不重名指的就是父类,重名指的就是子类
sysout(super.name+"在守护家园");//重名情况下访问父类属性用super关键字
}
}
类加载时,如果有父类先加载父类再加载子类
this是从本身开始找,本身没有找父亲,父亲没有找爷爷,爷爷没有找祖宗
super是从父亲开始找,父亲没有找爷爷,爷爷没有找祖宗
super调用不到爷爷的属性,前提是父亲存在重名属性,如果父亲不存在能调用到的
super:爹的东西,this:儿子的东西(变量、方法)
public class Person(){
protected String name="hahahha";
}
--------------------------------------------------------------------
public class Student extends Person(){
protected String name="aaaaa";
public void test(String name){
sysout(name);
sysout(this.name);
sysout(super.name);
}
}
---------------------------------------------------------------------
public class A(){
Student student =new Student() ;
student .test(lelelelel);
}
------------------------------------------------------------------------
sysout(name);//lelelelel
sysout(this.name);//aaaaa
sysout(super.name);//hahahha
注意:
- 私有无法被继承
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法,不写就是默认调用父类构造器
this 与super的比较
- 代表的对象不同:this 本身调用这个对象,super代表父类对象的英语
- 前提:this:没继承也能用,super:只能在继承的条件下使用
- 构造方法:this():本类的构造方法,super():父类的构造方法
3.继承之成员方法
1)成员方法不重复(方法名或参数不同),访问成员方法没有任何影响
2)成员方法重复(方法名和参数都相同)--->方法重写(覆盖)
方法的重写:对父类的方法进行升级
本类内:通过super去调用父类的重复方法
其他类:没有直接的办法调用到父类方法
静态方法是类的方法,非静态的是对象的方法。
静态(没有重写),方法的调用只和左边,定义的数据类型有关
public class B(){
public static void test(){
sysout("B");
}
}
----------------------------------------------------
public class Bextends B(){
public static void test(){
sysout("A");
}
}
----------------------------------------------------
public class App(){
A a = new A;
B b = new A;//父类的引用指向了子类
a.test();//A
b.test();//B
}
非静态(重写只跟非静态有关),重写(public)
public class B(){
public void test(){
sysout("B");
}
}
----------------------------------------------------
public class A extends B(){
@override
public void test(){
sysout("A");
}
}
----------------------------------------------------
public class App(){
A a = new A;
a.test();//A
B b = new A;
b.test();//A
}
重写的小结:快捷键Alt+Enter
- 需要有继承关系的两个类,子类重写父类的方法(只能重写方法)
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大 public>protected>defalut>private
- 抛出异常,范围,可以缩小,但是不能扩大 classNotFoundException-->Exception(大)
- 子类的方法必须和父类的一样,方法体不同
- 和返回值有关(返回值类型可以一致;对于引用数据类型来说,子类要小于等于父类(父类是object子类是string可以,反过来不行;))
继承的应用
this调用属性
/**
*父类Father
*子类Son
*测试类Demo
*this调用属性
*this调用方法
**/
//*****************Father*********************
public class Father{
public String name='jack';
public int age;
public void function(){
sysout(this.name);//father中的this是father类型的
this.eat();//调用的子类的eat方法,因为,成员方法在调用的时候看的是对象的实际对象(new的谁),this的实际对象Son
}
public void eat(){
sysout('father is eating now');
}
}
//*******************Son*******************
public class Son extends Father{
//如果子类里有重名的变量
public String name='rose';//①
public void meehod(){
sysout(this.name);//显示子类的名字,son类中的this类型就是son。
this.eat();//在son里调用eat方法,就是子类的方法
}
//子类里也有重名方法
public void eat(){
sysout('son is eating now');
}
}
//********************Demo******************
public class Demo{
public static void main (string args[]){
Son son =new Son();
son.mehtod();//子类中的,name是子类的name
son.function();//父类继承下来的,name是父类的;this.成员变量,调用的是谁看类型,this在哪个类中,this的类型就是谁;但this.成员方法的时候,是看new的是谁,就是那个对象
}
}
//这时执行son.mehtod(),显示的结果是son的名字,rose
//但如果删掉①,就找不到子类的名字,就往上找父类的,所以显示的结果是父类的Jack
//属性看类,方法看对象!!
this调用的是谁:属性看类,方法看对象
Father father=new Son();//多态的写法
father对象类型是?Father
father对象实际对象是?Son
4.继承之构造器
1)由于构造器的名称必须和类名称一致,所以子类是无法继承构造器的
2)构造器的作用:初始化成员变量
类加载的时候,是先加载父类再加载子类
实例化对象的时候,父类空间优于子类对象的产生(先执行父类的构造器,再执行子类的构造器)
每一个构造器里首行都默认有一行super(),调用父类的无参构造方法
要求:父类中必须存在无参构造器,否则默认情况会出错
super()如果显式创建,也必须在首行
/**
*
*
*
**/
构造器内存图补!!!!11.pm_11
5.java单继承
只能有一个直接父类,但可以有多个子类
具有局限性,后期接口会解决这个局限性
任何类都是有父类的,创建一个类的时候,如果没有显式继承父类,就是默认它的父类是object
6.super
super:指的是子类对象中的父类空间
this:指的是子类对象
用法:super.内容//调用父类的属性或方法
this.内容//调用自己的属性或者方法
共同点:找不到都会向上一级一级找
super(实参列表)//调用父类的构造器(对父类空间进行初始化)
this()调用本类的构造器
特点:都在构造器的第一行,不能同时出现
7.final
最终的,不可修改的访问修饰符
1)修饰类:被final修饰的类不能被继承,String就是final类
/**
*final修饰符修饰的类不能被继承
*
**/
final class super(){
public void method(){
}
}
2)修饰变量:该变量就变成常量(不能被修改)常量名建议大写用_链接
final修饰成员变量必须要要初始化!
/**
*final修饰变量
*
**/
class super {
private final String name='Amy'//必须有初始值;final和static谁在前都行
public void setName(String name){
this.name=name;//会报错,因为final修饰的变量就变成了常量不允许被修改
}
}
final修饰局部变量,可以不初始化的
/**
*final 修饰局部变量
*
**/
public void method(){
final int a;//可以不初始化
//使用时候第一次赋值就算初始化,之后的算修改
a=10;//初始化
a=20;//修改
}
3)修饰方法
该方法不能被重写,重载可以
/**
*
*final修饰方法,方法不允许被重写
**/
class Super{
public final void function(){
sysout();
}
}
class Sub extends Super {
public void function(){//会报错,方法不允许被重写
}
}
多态
定义:多态是指,同一行为具有不同的表现形式
前提:1.继承父类或者实现接口
2.必须有重写
3.父类引用指向子类对象
/**
*
*
**/
//************************Person类************************
public class Person{
private int id;
private String name;
public void eat(){
sysout('eating');
}
}
//************************Employee类************************
public class Employee extends Person{
private double salary;
@override
public void eat(){//重写父类方法
sysout('eating Employee lunch');
}
}
//************************Student类************************
public class Student extends Person{
private double score;
@override
public void eat(){//重写父类方法
sysout('eating Student lunch');
}
}
//************************Test类************************
public class Test{
public static void main (String[] args){
//父类的引用指向子类的对象
//new Employee();//子类对象
//new Student();
//正常应该是 Employee employee =new Employee();,但现在左边的引用是写成父类的
Person per1 = new Employee();//per1对象类型是Person,实际对象是Employee
Person per2 = new Student();//per2对象类型是Person,实际对象是Student
}
}
同一个方法,可以根据发送对象的不同而采用多种不同的行为方式:run()编译时才知道调用了谁?
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多
一个对象的实际类型是确定的
//new Student();
//new Person();
//可以指向的引用类型不确定了,父类的引用指向子类(父类可以调子)
//Student(eat方法、run方法)是Person(run方法)的子类
Student a = new Student(); //可执行eat方法、run方法
Person b = new Student();//可执行run方法
Object c = new Student();
- 能执行哪些方法,主要看左边的类型,和右边的关系不大
- 子类可以调用的方法不是自己的就是继承于父类的
- 父类可以指向子类,但不能调用子类的方法
多态的注意:
多态是方法的多态
父类和子类,有继承关系 (ClassCastException父子转换异常)
存在条件:继承关系,方法需要重写,父类引用子类对象 Father f1 = new Son();
不能重写的场合:
- static方法属于类,不属于实例
- final常量
- private方法私有不能重写
instanceof (引用类型的强制转换):判断两个类之间是否存在线性父子关系
public void test(){
//Object>String
//Object>Person>Teacher
//Object>Person>Student
Object object = new Student();
sysout(Object instanceof Student);//true
sysout(Object instanceof Person);//true
sysout(Object instanceof Object);//true
sysout(Object instanceof Teacher);//false
sysout(Object instanceof String);//false
Person person = new Student();//主要看对象判断是否有关
sysout(Person instanceof Student);//true
sysout(Person instanceof Person);//true
sysout(Person instanceof Object);//true
sysout(Person instanceof Teacher);//false
//sysout(Person instanceof String);//编译报错
}
类之间的转换:
父(高)-->子(低)需要强制转换;低转高,自动转换(多态),但可能丢失自己的一些方法
强制转换,是因为多态父类调用不了子类独有的内容,但就是很想调用(少见也要少用)
语法:子类类型 对象名 =(子类类型)父类引用
强转之前要先判断,前面的实际对象是否属于后面的类型
boolean flg=person instanceof Employee;//change要不就和后面的一样,要不就是后面的父类
sysout(flg);//ture
public class test{
main(){
Employee employee =new Employee();
Student student=new Student();
method(student);
}
public static void method(Person person){
//判断person的实际对象是什么
if(person instanceof Employee){
Employee employee =(Employee)person;
employee.working();
}else if (person instanceof Student){
Student student =(Student)person;
student.study();
}
}
}
语法:子类类型 对象名 =(子类类型)父类引用
Person change= new Student();//把change这个对象转换成Student类型,使用Students的类型方法
Student student =(Student)change;//Person转Student 强制转换
student.go();//go()是student里的方法
简写:
((Student)change).go();
- 父类引用子类的对象
- 把子类转成父类,向上转型
- 把父类转成子类,向下转型,强制转换
关键字
native 本地的,原生的,只能修饰方法,修饰的方法可以被重写
不能和abstract一起使用的修饰符?
final 不能一起修饰方法和类
static不能一起修饰方法
native不能一起修饰方法
private不能一起修饰方法
static和final一起使用
修饰方法:可以,因为都不能被重写
修饰成员变量:可以,表示静态常量
修饰局部变量:不可以,static不能修饰局部变量
修饰代码快:不可以,final不能修改代码块
修饰内部类:可以,一起修饰成员内部类,不能一起修饰局部内部类
Object根父类 默认是类的父类
该类中所有的方法可以被任意对象继承下去
构造器:无参构造器,供子类使用
方法:toString()
所有对象,在输出或者拼接的时候,都会默认调用该对象的toString方法
/**
*
*
*
**/
//*******************************toString**********************************
public class Test{
main(){
Employee employee =new Employee();
Object obj =new Object ();//这个对象没有什么意义,供子类使用
sysout(employee.toString());//输出的是经过处理的地址(object类中的toString方法
sysout(employee);//和上一行一样输出的经过处理的地址
//所有对象,在输出或者拼接的时候,都会默认调用该对象的toString方法
String str =new String("abc");
sysout(str);//输出值abc
}
}
//**object类中的toString方法
public String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
class getClass();反映位置,会遇到此方法
功能:返回对象的运行时类型(类加载的时候,会创建一个class对象)
hashCode();
将当前对象,通过哈希算法,得到一个int值,
两对相同对象(地址一样)经过相同的的hash算法,得到的int值是一样的。
两个不同的对象,经过相同的hash算法,得到的int值,不一定不相同
集合--》hashmap集合会遇到
finalize()
垃圾回收机制(自动的不定时回收)
Java中什么样的对象,会被认为是垃圾?没有引用的对象
垃圾对象被回收的时候,会默认调用该对象的finalize方法
目的:让这个对象做一个临终遗言(这个方法不是回收的代码)
equals(Object)
判断两个地址是否一致,实际和==没啥区别
但String类会重写equals,就直接比较值了
Static
代码块
{
}//匿名代码块,赋初始值
static{
//静态代码块,只执行一次
}
静态导入包
package com.java.method;
import static java.lang.Math.random;//静态导入包,关键字static
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());//正常不导入lang包
System.out.println(random());//导入lang包后可直接使用
System.out.println(PI);
}
}
被关键字final修饰后,就不能被继承了(断子绝孙了 。。。)
四、抽象类
抽象类:用关键字abstract修饰的,只有方法名,没有具体的实现,继承它的子类必须实现(父债子还)
抽象类不能new,只能靠子类去实现,抽象方法必须写在抽象类里
package com.java.method;
//abstract 抽象类:类 extends 类是单继承,接口可以多继承
public abstract class Action {
//只有方法名,没有方法
public void doSth(){
}
//抽象类不能new,只能靠子类去实现
//抽象方法必须写在抽象类里
}
//---------------------------------------------
package com.java.method;
//抽象的方法,继承他的子类必须实现(父债子还)
public class A extends Action {
@Override
public void doSth() {
System.out.println("...");
}
}
五、接口
接口:只有规范,自己无法写方法,比抽象类还抽象,约束和实现分离(面向接口编程)接口就是规范,接口的本质就是契约,是面向对象的精髓。(多继承 implements)
抽象类:具体实现和规范(抽象方法)都有(单继承 extends)
普通类:只有具体实现
接口里所有的方法都是public abstract的,接口不能被实例化,因为接口里没有构造方法。
关键词:interface、(实现一个接口,implements 接口,实现了接口就要重写接口里的方法)
package com.java.method;
public interface UserService {
//接口里的所有定义的方法都是 抽象的public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);//接口都需要有实现类
}
//--------------------------------------------------
package com.java.method;
public interface Time {
void time();
}
//---------------------------------------------------
package com.java.method;
//抽象类用extends
//一个类可以实现一个接口,implements 接口
//实现了接口的类,就要重写接口里的方法
public class UserServiceImpl implements UserService,Time{//可以多继承
@Override
public void time() {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
}
六、内部类
内部类就是在一个类中再定义一个类,可以通过内部类获取外部类的私有属性
package com.java.method;
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类的方法");
}
class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//获取外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
//-------------------------------------------------------------
package com.java.method;
public class Application {
public static void main(String[] args) {
Outer outer=new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer .new Inner ();
inner.in();
inner.getID();
}
}
内部类未完...