Scanner的使用
使用Scanner 要导入 import java.util.Scanner
Scanner sc = new Scanner(System.in);
int r=sc.nextInt();
输入String类型时用 .next();
Scanner sc = new Scanner(System.in);
String str=sc.next();
输入char类型时有两种方法
Scanner sc = new Scanner(System.in);
String chStr=sc.next();
char ch=chStr.charAt(0);
Scanner sc=new Scanner(System.in);
char ch=sc.next().charAt(0);
随机数
这个数在生成之前我们不确定这个数是多少
在java中依靠Math类帮助我们生成,这个类中有一个方法专门用来生成随机数:
Math.random 返回带正号的double 值,该值大于等于 0.0 且小于 1.0。
//输出 0-6以内的整数
System.out.println((int)(Math.random()*6));
方法的重载:
方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。
注意本质:重载的方法,实际是完全不同的方法,只是名称相同而已!
【2】构成方法重载的条件:
❀不同的含义:形参类型、形参个数、形参顺序不同
❀ 只有返回值不同不构成方法的重载
如:int a(String str){}与 void a(String str){}不构成方法重载
❀ 只有形参的名称不同,不构成方法的重载
如:int a(String str){}与int a(String s){}不构成方法重载
【3】代码:
public class TestMethod05{
public static void main(String[] args){
//10+20:
int sum = add(10,20);
System.out.println(sum);
//20+40+80:
//System.out.println(add(add(20,40),80));
System.out.println(add(20,40,80));
//30+60+90+120:
//System.out.println(add(add(30,60),add(90,120)));
System.out.println(add(30,60,90,120));
//9.8+4.7:
//System.out.println(add(9.8,4.7));
System.out.println(add(9.8,4.7));
}
//定义一个方法:两个数相加:两个int类型数据相加
public static int add(int num1,int num2){
return num1+num2;
}
//定义一个方法:三个数相加:
public static int add(int num1,int num2,int num3){
return num1+num2+num3;
}
//定义一个方法:四个数相加:
public static int add(int num1,int num2,int num3,int num4){
return num1+num2+num3+num4;
}
//定义一个方法:两个数相加:两个double类型的数据相加
public static double add(double num1,double num2){
return num1+num2;
}
}
数组的学习
数组变量属于引用类型,数组也是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。
//创建
arr = new int[4];//给数组开辟了一个长度为4的空间
//编译期声明和创建会被合为一句话: int[] arr = new int[4];
//通过数组一个属性来获取 length 长度
//arr.length
System.out.println("数组的长度是:"+arr.length);
增强for循环
优点:代码简单
缺点:单纯的增强for循环不能涉及跟索引相关的操作
//对score数组进行遍历,遍历出来的每一个元素都用int类型的num接收
for(int num:score){
System.out.println(num);
}
可变参数
作用提供了一个方法,参数的个数是可变的 ,解决了部分方法的重载问题
可变参数在JDK1.5之后加入的新特性
方法的内部对可变参数的处理跟数组是一样
可变参数和其他数据一起作为形参的时候,可变参数一定要放在最后
我们自己在写代码的时候,建议不要使用可变参数。
public static void main(String[] args){
method01(10);
method01();
method01(20,30,40);
method01(30,40,50,60,70);
}
public static void method01(int num2,int...num){
}
}
Arrays工具类
为了方便我们对数组进行操作,系统提供一个类Arrays,我们将它当做工具类来使用。
Arrays.toString(arr);
以 [] 和 ,和数组元素 组成字符串 的方式打印出数组
Arrays.binarySearch(arr,4)
查找 arr数组 的元素4所在位置
使用前提:一定要查看的是一个有序的数组
Arrays.sort(arr);
排序arr数组
copyOf 数组的复制
//复制 arr数组的前四个值给newArr数组
int[] newArr= Array.copyOf(arr,4);
copyOfRange 区间复制==[1,4)==
//复制[1,4)
int[] newArr=Array.copyOfRange(arr,1,4);
equals 比较两个数组的值是否一样
布尔类型 返回 ture 或者 false
Arrays.equals(arr1,arr2);
//println(arr1==arr2); 这个是错误的 两个数组地址不同 必为false
fill 数组的填充
//数组内值全部置为10
Arrays.fill(arr,10);
fill 数组的区间复制 重载
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。
Arrays.fill(int[] a, int fromIndex, int toIndex, int val)
System.arraycopy 数组的区间复制
System.arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
//src 源数组
//srcPos源数组起始位置
//dest目标数组
//destPos目标数据中的起始位置
//length 要复制的数组元素的数量
二维数组加强for遍历
public class TestArray15{
public static void main(String[] args){
//定义一个二维数组:
int[][] arr = new int[3][];//本质上定义了一个一维数组,长度为3
int[] a1 = {1,2,3};
arr[0] = a1;
arr[1] = new int[]{4,5,6,7};
arr[2] = new int[]{9,10};
//对二维数组遍历:
//方式1:外层普通for循环+内层普通for循环:
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
//方式2:外层普通for循环+内层增强for循环:
for(int i=0;i<arr.length;i++){
for(int num:arr[i]){
System.out.print(num+"\t");
}
System.out.println();
}
//方式3:外层增强for循环+内层增强for循环:
for(int[] a:arr){
for(int num:a){
System.out.print(num+"\t");
}
System.out.println();
}
//方式4:外层增强for循环+内层普通for循环:
for(int[] a:arr){
for(int i=0;i<a.length;i++){
System.out.print(a[i]+"\t");
}
System.out.println();
}
}
}
二维数组初始化方式
数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
静态初始化
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
int[][] arr = {{1,2},{4,5,6},{4,5,6,7,8,9,9}};
int[][] arr =new int[][] {{1,2},{4,5,6},{4,5,6,7,8,9,9}};
动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行。
int[][] arr = new int[3][]; //本质上定义了一维数组长度为3,每个“格子”中放入的是一个数组
arr[0] = {1,2};
arr[1] = {3,4,5,6};
arr[2] = {34,45,56};
int[][] arr = new int[3][2];
IDEA使用
在Eclipse中我们有Workspace (工作空间)和Project (工程)的概念,在IDEA中只有Project (工程)和Module (模块)的概念。
这里的对应关系为:
IDEA官网说明:
An Eclipse workspace is similar to a project in IntelliJ IDEA
An Eclipse project maps to a module in IntelliJ IDEA
翻译:
Eclipse中 workspace 相当于 IDEA中的Project
Eclipse中 Project 相当于 IDEA中的Module
在IntelliJ IDEA中Project(工程) 是最顶级的级别,次级别是Module(模块)。
一个Project下可以有多个Module。
out目录的说明:里面存放的是编译后的字节码文件
IDEA常用快捷键
创建内容:alt+insert
main方法:psvm
输出语句:sout
复制行:ctrl+d
删除行:ctrl+y
代码向上/下移动:Ctrl + Shift + Up / Down
搜索类: ctrl+n
生成代码 :alt + Insert(如构造函数等,getter,setter,hashCode,equals,toString)
百能快捷键 : alt + Enter (导包,生成变量等)
单行注释或多行注释 : Ctrl + / 或 Ctrl + Shift + /
代码块包围:try-catch,if,while等 ctrl+alt+t
撤回:ctrl+z
重命名 shift+f6
缩进:tab 取消缩进: shift+tab
代码一层一层调用的快捷键:点进源码:ctrl+鼠标悬浮在代码上+点进去即可:
显示代码结构 : alt + 7
显示导航栏: alt +1
代码模版
模板1: main方法:
main 或者 psvm
模板2:输出语句:
sout 或者 .sout
一些变型:
soutp:打印方法的形参
soutm:打印方法的名字
soutv:打印变量
模板3: 循环
普通for循环: fori(正向) 或者 .fori (正向) . forr(逆向)
增强for循环: iter 或者 .for
(可以用于数组的遍历,集合的遍历)
模板4: 条件判断
ifn 或者 .null :判断是否为null (if null)
inn 或者 .nn :判断不等于null (if not null)
模板5: 属性修饰符:
prsf : private static final
psf :public static final
面向对象三个阶段
面向对象三个阶段:
面向对象分析OOA – Object Oriented Analysis
对象:张三,王五,朱六,你,我
抽取出一个类----》人类
类里面有什么:
动词–》动态特性–》方法
名词–》静态特性–》属性
面向对象设计OOD – Object Oriented Design
先有类,再有对象:
类:人类: Person
对象:zhangsan ,lisi,zhuliu
面向对象编程OOP – Object Oriented Programming
局部变量和成员变量的区别
区别1:代码中位置不同
成员变量:类中方法外定义的变量
局部变量:方法中定义的变量 代码块中定义的变量
区别2:代码的作用范围
成员变量:当前类的很多方法
局部变量:当前一个方法(当前代码块)
区别3:是否有默认值
成员变量:有
局部变量:没有
引用数据类型: null
区别4:是否要初始化
成员变量:不需要,不建议初始化,后续使用的时候再赋值即可
局部变量:一定需要,不然直接使用的时候报错
区别5:内存中位置不同
成员变量:堆内存
局部变量:栈内存
区别6:作用时间不同
成员变量:当前对象从创建到销毁
局部变量:当前方法从开始执行到执行完毕
构造器
创建对象Person的过程:
1.第一次遇到Person的时候,进行类的加载(只加载一次)
2.创建对象,为这个对象在=堆中开辟空间
3.为对象进行属性的初始化动作
new关键字实际上是在调用一个方法,这个方法叫构造方法(构造器)
调用构造器的时候,如果你的类中没有写构造器,那么系统会默认给你分配一个构造器,只是我们看不到罢了。
可以自己显式 的将构造器编写出来:
构造器的格式:
[修饰符] 构造器的名字(){
}
构造器和方法的区别:
1.没有方法的返回值类型
2.方法体内部不能有return语句
3.构造器的名字很特殊,必须跟类名一样
构造器的作用:不是为了创建对象,因为在调用构造器之前,这个对象就已经创建好了,并且属性有默认的初始化的值。
调用构造器的目的是给属性进行赋值操作的。
注意:我们一般不会在空构造器中进行初始化操作,因为那样的话每个对象的属性就一样了。
实际上,我们只要保证空构造器的存在就可以了,里面的东西不用写
没有任何参数的构造器我们叫做:空参构造器–》空构造器
构造器的重载
一般保证空构造器的存在,空构造器中一般不会进行属性的赋值操作
一般我们会重载构造器,在重载的构造器中进行属性赋值操作
在重载构造器以后,假如空构造器忘写了,系统也不会给你分配默认的空构造器了,那么你要调用的话就会出错了。
当形参名字和属性名字重名的时候,会出现就近原则:在要表示对象的属性前加上this.来修饰 ,因为this代表的就是你创建的那个对象
public Person(String name,int age,double height){
//当形参名字和属性名字重名的时候,会出现就近原则:
//在要表示对象的属性前加上this.来修饰 ,因为this代表的就是你创建的那个对象
this.name = name;
this.age = age;
this.height = height;
}
This的使用
this关键字 用法:
(1)this可以修饰属性:
总结:当属性名字和形参发生重名的时候,或者 属性名字 和局部变量重名的时候,都会发生就近原则,所以如果我要是直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候如果我想要表示属性的话,在前面要加上:this.修饰
如果不发生重名问题的话,实际上你要是访问属性也可以省略this.
(2)this修饰方法:
总结:在同一个类中,方法可以互相调用,this.可以省略不写。
package com.msb4;
/**
* @Auther: msb-zhaoss
*/
public class Person {
//属性
int age;
String name;
double height;
//方法:
public void eat(){
int age = 10;
System.out.println(age);//就近原则,age指的是离它近的age--》局部变量的age
System.out.println(this.age);//这里指代的就是属性的age
System.out.println("我喜欢吃饭");
}
public void play(){
this.eat();
System.out.println("上网");
System.out.println("洗澡");
}
public void eat(){
System.out.println(this.age);
System.out.println("吃饭");
}
}
(3)this可以修饰构造器:
总结:同一个类中的构造器可以相互用this调用,注意:this修饰构造器必须放在第一行
public class Person {
//属性
int age;
String name;
double height;
//空构造器
public Person(){
}
//有参构造器
public Person(int age,String name,double height){
this(age,name);
this.height = height;
}
public Person(int age,String name){
this(age);
this.name = name;
}
public Person(int age){
this.age = age;
}
}
static
static可以修饰:属性,方法,代码块,内部类。
static修饰属性;
public class Test {
//属性:
int id;
static int sid;
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//创建一个Test类的具体的对象
Test t1 = new Test();
t1.id = 10;
t1.sid = 10;
Test t2 = new Test();
t2.id = 20;
t2.sid = 20;
Test t3 = new Test();
t3.id = 30;
t3.sid = 30;
//读取属性的值:
System.out.println(t1.id);
System.out.println(t2.id);
System.out.println(t3.id);
System.out.println(t1.sid);
System.out.println(t2.sid);
System.out.println(t3.sid);
}
}
一般官方的推荐访问方式:可以通过类名.属性名的方式去访问:
static修饰属性总结:
(1)在类加载的时候一起加载入方法区中的静态域中
(2)先于对象存在
(3)访问方式: 对象名.属性名 类名.属性名(推荐)
static修饰属性的应用场景:某些特定的数据想要在内存中共享,只有一块 --》这个情况下,就可以用static修饰的属性
属性:
静态属性 (类变量)
非静态属性(实例变量)
static修饰方法;
1.static和public都是修饰符,并列的没有先后顺序,先写谁后写谁都行
2.在静态方法中不能访问非静态的属性
3.在静态方法中不能访问非静态的方法
4.在静态方法中不能使用this关键字
5.非静态的方法可以用对象名.方法名去调用
6.静态的方法可以用 对象名.方法名去调用 也可以 用 类名.方法名 (推荐)
public class Demo {
int id;
static int sid;
public void a(){
System.out.println(id);
System.out.println(sid);
System.out.println("------a");
}
//1.static和public都是修饰符,并列的没有先后顺序,先写谁后写谁都行
static public void b(){
//System.out.println(this.id);//4.在静态方法中不能使用this关键字
//a();//3.在静态方法中不能访问非静态的方法
//System.out.println(id);//2.在静态方法中不能访问非静态的属性
System.out.println(sid);
System.out.println("------b");
}
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//5.非静态的方法可以用对象名.方法名去调用
Demo d = new Demo();
d.a();
//6.静态的方法可以用 对象名.方法名去调用 也可以 用 类名.方法名 (推荐)
Demo.b();
d.b();
}
}
代码块
类的组成:属性,方法,构造器,代码块,内部类
代码块分类:普通块,构造块,静态块,同步块(多线程)
代码:
public class Test {
//属性
int a;
static int sa;
//方法
public void a(){
System.out.println("-----a");
{
//普通块限制了局部变量的作用范围
System.out.println("这是普通块");
System.out.println("----000000");
int num = 10;
System.out.println(num);
}
//System.out.println(num);
//if(){}
//while(){}
}
public static void b(){
System.out.println("------b");
}
//构造块
{
System.out.println("------这是构造块");
}
//静态块
static{
System.out.println("-----这是静态块");
//在静态块中只能方法:静态属性,静态方法
System.out.println(sa);
b();
}
//构造器
public Test(){
System.out.println("这是空构造器");
}
public Test(int a){
this.a = a;
}
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
Test t = new Test();
t.a();
Test t2 = new Test();
t2.a();
}
}
总结:
(1)代码块执行顺序:
最先执行静态块,只在类加载的时候执行一次,所以一般以后实战写项目:创建工厂,数据库的初始化信息都放入静态块。
一般用于执行一些全局性的初始化操作。
再执行构造块,(不常用)
再执行构造器,
再执行方法中的普通块。
包 import
包的作用:为了解决重名问题(实际上包对应的就是盘符上的目录),解决权限问题
包名定义:
(1)名字全部小写
(2)中间用.隔开
(3)一般都是公司域名倒着写 : com.jd com.msb
(4)加上模块名字:com.jd.login com.jd.register
(5)不能使用系统中的关键字:nul,con,com1—com9…
(6)包声明的位置一般都在非注释性代码的第一行:
导包问题:
//声明包:
package com.msb7;
import com.msb2.Person; //导包:就是为了进行定位
import java.util.Date;
/**
* @Auther: msb-zhaoss
*/
public class Test {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
new Person();
new Date();
new java.sql.Date(1000L);//在导包以后,还想用其他包下同名的类,就必须要手动自己写所在的包。
new Demo();
}
}
总结:
(1)使用不同包下的类要需要导包: import **..; 例如:import java.util.Date;
(2)在导包以后,还想用其他包下同名的类,就必须要手动自己写所在的包。
(3)同一个包下的类想使用不需要导包,可以直接使用。
(4)在java.lang包下的类,可以直接使用无需导包:
System.out.println(Math.random());
(5)IDEA中导包快捷键:alt+enter
可以自己设置自动导包
(6)可以直接导入*:
/*import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;*/
import java.util.*;//代表所有
在Java中的导包没有包含和被包含的关系:
设置目录平级的格式(不是包含和被包含的显示):
静态导入
//静态导入:
import static java.lang.Math.*;
//导入:java.lang下的Math类中的所有静态的内容
public class Test {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
System.out.println(round(5.6));
}
//在静态导入后,同一个类中有相同的方法的时候,会优先走自己定义的方法。
public static int round(double a){
return 1000;
}
}
三大特性
封装
封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装是一种信息隐藏技术,在java中通过关键字private,protected和public实现封装。什么是封装﹖封装把对象的所有组成部分组合在一起,封装定义程序如何引用对象的数据,封装实际上使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。适当的封装可以让程式码更容易理解和维护,也加强了程式码的安全性。
我们程序设计追求“高内聚,低耦合”。
➢高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
➢低耦合:仅对外暴露少量的方法用于使用。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提
高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露
的暴露出来。这就是封装性的设计思想。
封装的好处:
提高代码的安全性
代码:通过一个属性感受封装:
public class Girl {//女孩
//属性:
private int age;
//读取年龄:
public int duquAge(){
return age;
}
//设置年龄:
public void shezhiAge(int age){
if(age >= 30 ){
this.age = 18;
}else{
this.age = age;
}
}
}
public class Test {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//创建一个Girl类的对象:
Girl g = new Girl();
/*g.age = 33;
System.out.println(g.age);*/
//设置年龄:
g.shezhiAge(31);
//读取年龄:
System.out.println(g.duquAge());
}
}
上面的代码,对于属性age来说,我加了修饰符private,这样外界对它的访问就受到了限制,现在我还想加上其他的限制条件,但是在属性本身上没有办法再加了,所以我们通过定义方法来进行限制条件的添加。
以属性为案例:
进行封装:
将属性私有化,被private修饰–》加入权限修饰符
一旦加入了权限修饰符,其他人就不可以随意的获取这个属性
提供public修饰的方法让别人来访问/使用
即使外界可以通过方法来访问属性了,但是也不能随意访问,因为咱们在方法中可以加入 限制条件。
实际开发中,方法一般会写成 setter,getter方法:
可以利用IDEA快捷键生成:alt+insert -->getter and setter:
public class Girl {//女孩
//属性:
private int age;
//读取年龄:
public int getAge(){
return age;
}
//设置年龄:
public void setAge(int age){
if(age >= 30 ){
this.age = 18;
}else{
this.age = age;
}
}
}
加深练习:
public class Student {
//属性:
private int age;
private String name;
private String sex;
//加入对应的setter和getter方法:
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
if("男".equals(sex) || "女".equals(sex) ){//sex是男 或者 是 女
this.sex = sex;
}else{
this.sex = "男";
}
}
//加入构造器:
public Student(){
}
public Student(int age,String name,String sex){
this.age = age;
this.name = name;
//this.sex = sex;
this.setSex(sex);
}
}
public class Test {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//创建一个Student对象:
Student s1 = new Student();
s1.setName("nana");
s1.setAge(19);
s1.setSex("女");
System.out.println(s1.getName()+"---"+s1.getAge()+"----"+s1.getSex());
Student s2 = new Student(18,"菲菲","asdfasdfsadf");
System.out.println(s2.getName()+"---"+s2.getAge()+"----"+s2.getSex());
}
}
继承
类是对对象的抽象
继承是对类的抽象
继承的好处:提高代码的复用性
父类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了
需要注意的点:
父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用。
总结:
(1)继承关系 :
父类/基类/超类
子类/派生类
子类继承父类一定在合理的范围进行继承的 子类 extends 父类
(2)继承的好处:
1.提高了代码的复用性,父类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了
2.便于代码的扩展
3.为了以后多态的使用。是多态的前提。
(3)父类private修饰的内容,子类也继承过来了。
(4)一个父类可以有多个子类。
(5)一个子类只能有一个直接父类。
但是可以间接的继承自其它类。
(6)继承具有传递性:
Student --》继承自 Person —》继承自Object
Object类是所有类的根基父类。
所有的类都直接或者间接的继承自Object。
权限修饰符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5IxJIGMR-1625747891714)(C:\Users\Boucy\AppData\Roaming\Typora\typora-user-images\image-20210705234417615.png)]
private:权限:在当前类中可以访问
default:缺省修饰符:权限:到同一个包下的其他类都可以访问
protected:权限:最大到不同包下的子类
public:在整个项目中都可以访问
以后写代码
一般属性:用private修饰 ,方法:用public修饰
方法的重写
重写:
发生在子类和父类中,当子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
重写有严格的格式要求:
子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。
重载和重写的区别:
重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载
重写:在不同的类中,子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHeFRmdT-1625747891717)(C:\Users\Boucy\AppData\Roaming\Typora\typora-user-images\image-20210705235936705.png)]
super
super:指的是: 父类的
super可以修饰属性,可以修饰方法;
在子类的方法中,可以通过 super.属性 super.方法 的方式,显示的去调用父类提供的属性,方法。在通常情况下,super.可以省略不写:
在特殊情况下,当子类和父类的属性重名时,你要想使用父类的属性,必须加上修饰符super.,只能通过super.属性来调用
在特殊情况下,当子类和父类的方法重名时,你要想使用父类的方法,必须加上修饰符super.,只能通过super.方法来调用
在这种情况下,super.就不可以省略不写。
super修饰构造器:
其实我们平时写的构造器的第一行都有:super() -->作用:调用父类的空构造器,只是我们一般都省略不写
(所有构造器的第一行默认情况下都有super(),但是一旦你的构造器中显示的使用super调用了父类构造器,那么这个super()就不会给你默认分配了。如果构造器中没有显示的调用父类构造器的话,那么第一行都有super(),可以省略不写)
如果构造器中已经显示的调用super父类构造器,那么它的第一行就没有默认分配的super();了
在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存:
因为super修饰构造器要放在第一行,this修饰构造器也要放在第一行:
写代码构造器的生成可以直接使用IDEA提供的快捷键:
alt+insert
Object类
所有类都直接或间接的继承自Object类,Object类是所有Java类的根基类。
也就意味着所有的Java对象都拥有Object类的属性和方法。
如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。
toString()方法
==Object类的toString()==的作用:
返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
返回:
该对象的字符串表示形式。
现在,使用toString方法的时候,打印出来的东西 “不好看”,对于其他人来说不友好,可读性不好
我们现在是想知道对象的信息,名字,年龄,身高。。。。。。
现在的格式不好:
出现的问题:子类Student对父类Object提供的toString方法不满意,不满意–》对toString方法进行重写:
总结:toString的作用就是对对象进行“自我介绍”,一般子类对父类提供的toString都不满意,都要进行重写。
IDEA提供了快捷键
equals方法
equals作用:这个方法提供了对对象的内容是否相等 的一个比较方式,对象的内容指的就是属性。
父类Object提供的equals就是在比较地址==,没有实际的意义, 我们一般不会直接使用父类提供的方法,
而是在子类中对这个方法进行重写。==
IDEA提供了快捷键
instanceof运算符
a instanceof b
判断a对象是否是b这个类的实例 如果是返回true 如果不是返回false
类和类的关系
类和类可以产生关系:
将一个类作为另一个类中的方法的形参
将一个类作为另一个类的属性
多态
多态跟属性无关,多态指的是方法的多态,而不是属性的多态。
总结:
先有父类,再有子类:–》继承 先有子类,再抽取父类 ----》泛化
什么是多态:
多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。
多态指的就是同一个方法调用,然后由于对象不同会产生不同的行为。
多态的好处:
为了提高代码的扩展性,符合面向对象的设计原则:开闭原则。
开闭原则:指的就是扩展是 开放的,修改是关闭的。
注意:多态可以提高扩展性,但是扩展性没有达到最好,以后我们会学习 反射
多态的要素:
一,继承: Cat extends Animal ,Pig extends Animal, Dog extends Animal
二,重写:子类对父类的方法shout()重写
三,父类引用指向子类对象:
Pig p = new Pig();
Animal an = p;
将上面的代码合为一句话:
Animal an = new Pig();
=左侧:编译期的类型
=右侧:运行期的类型
向下转型
目的是为了获取子类特有的内容
简单工厂设计模式
不仅可以使用父类做方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象。
简单工厂模式的实现,它是解决大量对象创建问题的一个解决方案。将创建和使用分开,工厂负责创建,使用者直接调用即可。简单工厂模式的基本要求是
² 定义一个static方法,通过类名直接调用
² 返回值类型是父类类型,返回的可以是其任意子类类型
² 传入一个字符串类型的参数,工厂根据参数创建对应的子类产品
public class Test {
public static void main(String[] args) {
Girl g = new Girl();
//Cat c = new Cat();
//Dog d = new Dog();
//Pig p = new Pig();
Animal an = PetStore.getAnimal("狗");
g.play(an);
}
}
public class PetStore {//宠物店 ---》工厂类
//方法:提供动物
public static Animal getAnimal(String petName){//多态的应用场合(二)
Animal an = null;
//petName可能为空,防止触发空指针异常
//"猫".equals(petName) 建议!!
//petName.equals("猫") 不建议
if("猫".equals(petName)){//petName.equals("猫") --》这样写容易发生空指针异常
an = new Cat();
}
if("狗".equals(petName)){
an = new Dog();
}
if("猪".equals(petName)){
an = new Pig();
}
return an;
}
}
final
final修饰一个变量,变量的值不可以改变,这个变量也变成了一个字符常量,约定俗称的规定:名字大写
final修饰引用数据类型,那么地址值就不可以改变
final修饰方法,那么这个方法不可以被该类的子类重写:
final修饰类,代表没有子类,该类不可以被继承,一旦一个类被final修饰,那么里面的方法也没有必要用final修饰了(final可以省略不写)
案例:JDK提供的Math类:看源码发现:
(1)使用Math类的时候无需导包,直接使用即可:
(2)Math类没有子类,不能被其他类继承了
(3)里面的属性全部被final修饰,方法也是被final修饰的,只是省略不写了
原因:子类没有必要进行重写。
(4)外界不可以创建对象:
Math m = new Math();
(5)发现Math类中的所有的属性,方法都被static修饰
那么不用创建对象去调用,只能通过类名.属性名 类名.方法名 去调用
抽象类 抽象方法
抽象类和抽象方法的关系:
抽象类中可以定义0-n个抽象方法。
抽象类作用:
在抽象类中定义抽象方法,目的是为了为子类提供一个通用的模板,子类可以在模板的基础上进行开发,先重写父类的抽象方法,然后可以扩展子类自己的内容。抽象类设计避免了子类设计的随意性,通过抽象类,子类的设计变得更加严格,进行某些程度上的限制。使子类更加的通用。
在一个类中,会有一类方法,子类对这个方法非常满意,无需重写,直接使用
在一个类中,会有一类方法,子类对这个方法永远不满意,会对这个方法进行重写。
一个方法的方法体去掉,然后被abstract修饰,那么这个方法就变成了一个抽象方法
一个类中如果有方法是抽象方法,那么这个类也要变成一个抽象类。
一个抽象类中可以有0-n个抽象方法
抽象类可以被其他类继承:
一个类继承一个抽象类,那么这个类可以变成抽象类
一般子类不会加abstract修饰,一般会让子类重写父类中的抽象方法
子类继承抽象类,就必须重写全部的抽象方法
子类如果没有重写父类全部的抽象方法,那么子类也可以变成一个抽象类。
创建抽象类的对象:–>抽象类不可以创建对象
抽象类不能创建对象,那么抽象类中是否有构造器?
抽象类中一定有构造器。构造器的作用 给子类初始化对象的时候要先super调用父类的构造器。
抽象类是否可以被final修饰?
==不能被final修饰,因为抽象类设计的初衷就是给子类继承用的。==要是被final修饰了这个抽象类了,就不存在继承了,就没有子类。
接口
1.类是类,接口是接口,它们是同一层次的概念。
2.接口中没有构造器
3.接口如何声明:interface
4.在JDK1.8之前,接口中只有两部分内容:
(1)常量:固定修饰符:public static final
(2)抽象方法:固定修饰符:public abstract
注意:修饰符可以省略不写,IDE会帮你自动补全,但是初学者建议写上,防止遗忘。
5.类和接口的关系是什么? 实现关系 类实现接口:
6.一旦实现一个接口,那么实现类要重写接口中的全部的抽象方法:
7.如果没有全部重写抽象方法,那么这个类可以变成一个抽象类。
8.java只有单继承,java还有多实现
一个类继承其他类,只能直接继承一个父类
但是实现类实现接口的话,可以实现多个接口
9.写法:先继承 再实现:extends Person implements TestInterface01,TestInterface02
10.接口不能创建对象:
11.接口中常量如何访问:
/**
* 1.类是类,接口是接口,它们是同一层次的概念。
* 2.接口中没有构造器
* 3.接口如何声明:interface
* 4.在JDK1.8之前,接口中只有两部分内容:
* (1)常量:固定修饰符:public static final
* (2)抽象方法:固定修饰符:public abstract
* 注意:修饰符可以省略不写,IDE会帮你自动补全,但是初学者建议写上,防止遗忘。
*/
public interface TestInterface01 {
//常量:
/*public static final*/ int NUM = 10;
//抽象方法:
/*public abstract*/ void a();
/*public abstract*/ void b(int num);
/*public abstract*/ int c(String name);
}
interface TestInterface02{
void e();
void f();
}
/*
5.类和接口的关系是什么? 实现关系 类实现接口:x`
6.一旦实现一个接口,那么实现类要重写接口中的全部的抽象方法:
7.如果没有全部重写抽象方法,那么这个类可以变成一个抽象类。
8.java只有单继承,java还有多实现
一个类继承其他类,只能直接继承一个父类
但是实现类实现接口的话,可以实现多个接口
9.写法:先继承 再实现:extends Person implements TestInterface01,TestInterface02
*/
class Student extends Person implements TestInterface01,TestInterface02 {
@Override
public void a() {
System.out.println("---1");
}
@Override
public void b(int num) {
System.out.println("---2");
}
@Override
public int c(String name) {
return 100;
}
@Override
public void e() {
System.out.println("---3");
}
@Override
public void f() {
System.out.println("---4");
}
}
class Test{
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//10.接口不能创建对象:
//TestInterface02 t = new TestInterface02();
TestInterface02 t = new Student();//接口指向实现类 ---》多态
//11.接口中常量如何访问:
System.out.println(TestInterface01.NUM);
System.out.println(Student.NUM);
Student s = new Student();
System.out.println(s.NUM);
TestInterface01 t2 = new Student();
System.out.println(t2.NUM);
}
}
接口的作用是什么?
定义规则,只是跟抽象类不同地方在哪?它是接口不是类。
接口定义好规则之后,实现类负责实现即可。
【5】多态的应用场合:
(1)父类当做方法的形参,传入具体的子类的对象
(2)父类当做方法的返回值,返回的是具体的子类的对象
(3)接口当做方法的形参,传入具体的实现类的对象
(4)接口当做方法的返回值,返回的是具体的实现类的对象
接口和抽象类的区别:
抽象类:
1、抽象类使用abstract修饰;
2、抽象类不能实例化,即不能使用new关键字来实例化对象;
3、含有抽象方法(使用abstract关键字修饰的方法)的类是抽象类,必须使用abstract关键字修饰;
4、抽象类可以含有抽象方法,也可以不包含抽象方法,抽象类中可以有具体的方法;
5、如果一个子类实现了父类(抽象类)的所有抽象方法,那么该子类可以不必是抽象类,否则就是抽象类;
6、抽象类中的抽象方法只有方法体,没有具体实现;
接口:
1、接口使用interface修饰;
2、接口不能被实例化;
3、一个类只能继承一个类,但是可以实现多个接口;
4、接口中方法均为抽象方法;
5、接口中不能包含实例域或静态方法(静态方法必须实现,接口中方法是抽象方法,不能实现)
在JDK1.8之前,接口中只有两部分内容:
(1)常量:固定修饰符:public static final
(2)抽象方法:固定修饰符:public abstract
在JDK1.8之后,新增非抽象方法:
(1)被public default修饰的非抽象方法:
注意1:default修饰符必须要加上,否则出错
注意2:实现类中要是想重写接口中的非抽象方法,那么default修饰符必须不能加,否则出错。
public interface TestInterface {
//常量:
public static final int NUM= 10;
//抽象方法:
public abstract void a();
//public default修饰的非抽象方法:
public default void b(){
System.out.println("-------TestInterface---b()-----");
}
}
class Test implements TestInterface{
public void c(){
//用一下接口中的b方法:
b();//可以
//super.b();不可以
TestInterface.super.b();//可以
}
@Override
public void a() {
System.out.println("重写了a方法");
}
@Override
public void b() {
}
}
(2)静态方法:
注意1:static不可以省略不写
注意2:静态方法不能重写
public interface TestInterface2 {
//常量:
public static final int NUM = 10;
//抽象方法:
public abstract void a();
//public default非抽象方法;
public default void b(){
System.out.println("-----TestInterface2---b");
}
//静态方法:
public static void c(){
System.out.println("TestInterface2中的静态方法");
}
}
class Demo implements TestInterface2{
@Override
public void a() {
System.out.println("重写了a方法");
}
public static void c(){
System.out.println("Demo中的静态方法");
}
}
class A {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
Demo d = new Demo();
d.c();
Demo.c();
TestInterface2.c();
}
}
疑问:为什么要在接口中加入非抽象方法???
如果接口中只能定义抽象方法的话,那么我要是修改接口中的内容,那么对实现类的影响太大了,所有实现类都会受到影响。
现在在接口中加入非抽象方法,对实现类没有影响,想调用就去调用即可。
内部类
- 1.类的组成:属性,方法,构造器,代码块(普通块,静态块,构造块,同步块),内部类
- 2.一个类TestOuter的内部的类SubTest叫内部类, 内部类 :SubTest 外部类:TestOuter
- 3.内部类:成员内部类 (静态的,非静态的) 和 局部内部类(位置:方法内,块内,构造器内)
- 4.成员内部类:
- 里面属性,方法,构造器等
- 修饰符:private,default,protect,public,final,abstract
成员内部类
public class TestOuter {
//非静态的成员内部类:
public class D{
int age = 20;
String name;
public void method(){
//5.内部类可以访问外部类的内容
/*System.out.println(age);
a();*/
int age = 30;
//8.内部类和外部类属性重名的时候,如何进行调用:
System.out.println(age);//30
System.out.println(this.age);//20
System.out.println(TestOuter.this.age);//10
}
}
//静态成员内部类:
static class E{
public void method(){
//6.静态内部类中只能访问外部类中被static修饰的内容
/*System.out.println(age);
a();*/
}
}
//属性:
int age = 10;
//方法:
public void a(){
System.out.println("这是a方法");
{
System.out.println("这是一个普通块");
class B{
}
}
class A{
}
//7.外部类想要访问内部类的东西,需要创建内部类的对象然后进行调用
D d = new D();
System.out.println(d.name);
d.method();
}
static{
System.out.println("这是静态块");
}
{
System.out.println("这是构造块");
}
//构造器:
public TestOuter(){
class C{
}
}
public TestOuter(int age) {
this.age = age;
}
}
class Demo{
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
//创建外部类的对象:
TestOuter to = new TestOuter();
to.a();
//9.创建内部类的对象:
//静态的成员内部类创建对象:
TestOuter.E e = new TestOuter.E();
//非静态的成员内部类创建对象:
//错误:TestOuter.D d = new TestOuter.D();
TestOuter t = new TestOuter();
TestOuter.D d = t.new D();
}
}
局部内部类
public class TestOuter {
//1.在局部内部类中访问到的变量必须是被final修饰的
public void method(){
final int num = 10;
class A{
public void a(){
//num = 20;
System.out.println(num);
}
}
}
//2.如果类B在整个项目中只使用一次,那么就没有必要单独创建一个B类,使用内部类就可以了
public Comparable method2(){
class B implements Comparable{
@Override
public int compareTo(Object o) {
return 100;
}
}
return new B();
}
public Comparable method3(){
//3.匿名内部类
return new Comparable(){
@Override
public int compareTo(Object o) {
return 200;
}
};
}
public void teat(){
Comparable com = new Comparable(){
@Override
public int compareTo(Object o) {
return 200;
}
};
System.out.println(com.compareTo("abc"));
}
}