- 笔记参考来源狂神说Java视频
https://www.bilibili.com/video/BV12J41137hu
- 本篇笔记有点长,可以根据目录定位,建议配合视频学习。
软件及软件开发
计算机软件
基本的Dos命令
常用的Dos命令
# 打开计算器 calc
# 打开画图 mspaint
# 新建记事本 notepad
Java流程控制
用户交互Scanner
- 之前我们学的基本语法并没有实现程序和人的交互,Java给我们提供了一个工具类,可以获取用户的输入。
- java.util.Scanner是Java5的新特征,我们通过Scanner类来获取用户的输入。
- 基本语法
Scanner s = new Scanner(System.in);
- 通过Scanner类的 next()与 nextLine()方法获取用户的字符串,
- 读取前一般用hasNext()与hasNextLine()判断是否还有输入的数据。
next()
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("使用next方法接收:");
//判断用户有没有输入字符串
if(scanner.hasNext()){//还有输入
//使用next方式接收
String sstr = scanner.next();
System.out.println("输出的内容为:"+sstr);
}
//凡是属于IO流的类如果不关闭会一直占用资源,要养成好习惯,用完就关掉
scanner.close();
}
}
结果:
根据以上例子可总结:
- 一定要读取到有效字符才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法会将其去掉
- 只有输入有效字符后才将其后面输入的空白作为结束符
- next()不能得到带有空格的字符串
nextLine()
public static void main(String[] args) {
//从键盘接收数据
Scanner scanner = new Scanner(System.in);
System.out.println("使用nextLine方法接收:");
//判断用户有没有输入字符串
if(scanner.hasNextLine()){//还有输入
//使用next方式接收
String sstr = scanner.nextLine();
System.out.println("输出的内容为:"+sstr);
}
//凡是属于IO流的类如果不关闭会一直占用资源,要养成好习惯,用完就关掉
scanner.close();
}
结果:
根据以上例子可总结:
- 以Enter作为结束符,即返回输入回车之前所有的字符
- nextLine()可以获取空白
也可以不加条件语句:
//从键盘接收数据
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数据:");
String sstr = scanner.nextLine();
System.out.println("输出的内容为:"+sstr);
scanner.close();
if判断:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int i=0;
System.out.println("请输入整数:");
if(scanner.hasNextInt()){//还有输入
//使用next方式接收
i = scanner.nextInt();
System.out.println("输出的整数数据为:"+i);
}else{
System.out.println("你输入的不是整数数据");
}
scanner.close();
}
}
实践:
public static void main(String[] args) {
/*我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入
非数字来结束输入,并输出非法结果;
*/
Scanner scanner = new Scanner(System.in);
//和
double sum = 0;
//计算输入了多少个数字
int m = 0;
//通过循环判断是否还有输入,并在里面对每一次进行求和统计
while(scanner.hasNextDouble()){
double x = scanner.nextDouble();
m = m + 1;//m++
sum = sum + x;
System.out.println("你输入了第"+m+"个数据,然后当前结果sum="+sum);
}
System.out.println(m+"个数的和为"+sum);
System.out.println(m+"个数的平均值"+(sum/m));
scanner.close();
}
结果:
10
你输入了第1个数据,然后当前结果sum=10.0
20
你输入了第2个数据,然后当前结果sum=30.0
r
2个数的和为30.0
2个数的平均值15.0
Process finished with exit code 0
循环结构
- while循环
//计算1+2+3+...+100
int i = 0;
int sum = 0;
while(i < 100){
i++;
sum+=i;
}
System.out.println(sum);//5050
- do…while循环
//先执行后判断,至少执行一次
do{
i++;
sum+=i;
}while(i < 100) //5050
- for循环
//(初始化;条件判断;迭代)
for(int i = 0;i <100;i++){
i++;
sum+=i;
}
for(;;){...}//死循环
- 练习一
//练习1:计算0到100之间的奇数和偶数的和
int oddSum = 0;
int evenSum = 0;
for(int i =0;i < 100;i++){
if(i %2 !=0){//奇数
oddSum+=i;
}else{
evenSum+=i; //偶数
}
}
System.out.println("奇数的和:"+oddSum);
System.out.println("偶数的和:"+evenSum);
- 练习二
//练习二:输出1-1000能被5整除的数,每行输出3个
for(int i = 1;i <1000;i++){
if(i%5==0){
System.out.print(i+"\t");//不换行,数字之间隔一个tab
}
if(i%(5*3)==0){//每行打印3个
System.out.println();//换行
//另外一种形式换行
//System.out.println("\n");
}
}
- 练习三
步骤:
1、我们先打印第一列
2、我们固定的1再用一个循环包起来
3、去掉重复项,i<=j
4、调整样式
//练习三、打印九九乘法表
// 嵌套for循环来解决
for (int j = 1; j <= 9; j++) {
for (int i = 1; i <=j; i++) {
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
增强for循环
int[] numbers = {10,20,30,40,50};//定义一个数组
for(int x:numbers){
System.out.println(x); //遍历数组的元素10 20 30 40 50
}
//相当于
for(int i = 0;i < 5;i++){
System.out.println(numbers[i]);
}
流程控制练习
//打印三角形 5 行
for (int i = 1; i <= 5; i++) {
for (int j = 5; j >= i; j--) {
System.out.print(" ");
}
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
for (int j = 1; j < i; j++) {
System.out.print("!");
}
System.out.println();
}
面向对象
封装
-
该露的露,该藏的藏
- 我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据细节由自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
-
封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,称为信息隐藏。
-
作用
1. 提高程序的安全性,保护数据 2. 隐藏代码的实现细节 3. 统一接口 4. 系统可维护性增加了
例子:
Student类
package kuangshen.demo04;
//类 private私有
public class Student {
// 属性私有
private String name; //名字
private int id;//学号
private char sex;//性别
private int age;//年龄
// 提供一些可以操作这个属性的方法!
//提供一些public的get、set方法
//get 获得这个数据
public String getName(){
return this.name;
}
//set 给这个数据设置值
public void setName(String name){
this.name = name;
}
//alt+insert
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 120 || age <0 ){
this.age = 3;
}else{
this.age = age;
}
}
}
Application类
package kuangshen.demo04;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("bail");
//s1.getName().sout
System.out.println(s1.getName());
s1.setAge(999);
System.out.println(s1.getAge());
}
}
继承
- 继承的本质是对某一批类的抽象,从而实现对世界更好地建模。
- extends的意思是”扩展“。子类是父类的扩展,使用关键字extends来表示。
- Java中类只有单继承,没有多继承!一个类只能继承一个父类。
- 继承是类与类之间的一种关系,此外还有依赖、组合、聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为**父类(基类)**子类继承父类。
- 子类和父类之间,从意义上讲应该具有”is a“的关系。
//学生类(子类)继承 人类(父类)
public class Student extends Person{ /*Person extends Object*/
...
}
- 子类继承了父类,就会拥有父类的全部方法,而private私有属性及方法无法继承。
- 在Java中,所有类,都默认直接或间接继承Object类 (Ctrl+H 可以查看类关系)
- 被final修饰的类,无法被继承(断子绝孙)。
Person类
package kuangshen.demo04;
//Person 人 :父类
public class Person {
private int money = 10_0000_0000;
public void say(){
System.out.println("Hello World!");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
Student类
package kuangshen.demo04;
//学生 is 人:派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person{
}
package kuangshen.demo04;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.say();
System.out.println(s1.getMoney());
}
}
super & this
- super()调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或构造方法中
- **super()和this()**不能同时调用构造方法,因为this也必须写在第一行
super与this的区别:
super代表父类对象的引用,只能在继承条件下使用;this调用自身对象,没有继承也可以使用。
构造方法:
this();本类的构造
super();父类的构造
super(); //隐藏代码,默认调用了父类的无参构造,要写只能写第一行
方法的重写
- 重写:子类的方法必须与父类方法必须一致,方法体不同。
- 重写是方法的重写,与属性无关
- 重写方法只与非静态方法有关,与静态方法无关(静态方法不能被重写)
public class B {
public static void test(){ //静态方法
System.out.println("B==>test()");
}
}
public class A extends B{ //继承
public static void test(){
System.out.println("A==>test()");
}
}
public class Application {
public static void main(String[] args) {
//方法的调用之和左边定义的类型有关
A a = new A();
a.test(); //打印 A==>test()
//父类的引用指向了子类,但静态方法没有被重写
B b = new A();
b.test(); //打印 B==>test()
}
}
修改A.java, B.java
public class B {
public void test(){ //非静态方法
System.out.println("B==>test()");
}
}
public class A extends B{
@Override //重写了B的方法
public void test() {
System.out.println("A==>test()");
}
}
//父类的引用指向了子类
B b = new A(); //子类重写了父类的方法,执行子类的方法
b.test(); //打印变成了 A==>test()
/*
静态方法是类的方法,非静态方法是对象的方法
有static时,b调用了B类的方法,因为b是b类定义的
没有static时,b调用的是对象的方法,而b是A类new出来的对象,调用A的方法
*/
-
重写:需要有继承关系,子类重写父类的方法!
-
静态方法属于类,非静态方法属于对象
-
注意点:
1、方法名、参数列表必须相同 2、修饰符范围可以扩大,不能缩小(public>protected>Default>private) 3、抛出的异常 范围可以被缩小,不能扩大 ClassNotFoundException-->Exception(大) 4、被**static(属于类,不属于实例),final(常量方法),private(私有)**修饰的方法不能重写
为什么需要重写:
1、父类的功能:子类不一定需要,或者不一定满足!
Alt+Insert: override;
方法的重载
区别:重载实现于一个类中;重写实现于子类中。
重载(Overload):是一个类中多态性的一种表现,指同一个类中不同的函数使用相同的函数名,但是函数的参数个数或类型不同。可以有不同的返回类型;可以有不同的访问修饰符;可以抛出不同的异常。调用的时候根据函数的参数来区别不同的函数。
重写(Override):父类与子类之间的多态性,是子类对父类函数的重新实现。函数名和参数与父类一样,子类与父类函数体内容不一样。子类返回的类型必须与父类保持一致;子类方法访问修饰符的限制一定要大于父类方法的访问修饰(public>protected>default>private);子类重写方法一定不能抛出新的检查异常或者比被父类方法申明更加宽泛的检查型异常。
重载
多态
-
动态编译:类型
-
即同一方法可以根据发送对象的不同而采用不同的行为方式(多态的意义)
-
一个对象的实际类型是确定的,但可以指向对象的引用可以有很多(一般指父类,有关系的类)
-
多态存在条件
- 有继承关系 - 子类重写父类方法 - 父类引用指向子类对象
注意点:
- 多态是方法的多态,没有属性的多态
- 父类和子类,有联系 类型转换异常: ClassCastException
- 存在条件:继承关系,方法需要重写(若不重写,调用的都是各自自己的方法,那就没有任何区别了),父类引用指向子类对象!father s1 = new Son();
不能重写,不能实现多态的情况:
1、static 方法属于类,它不属于实例
2、final常量
3、private方法;
instanceof和类型转换
- instanceof 引用类型比较,判断一个对象是什么类型
public class Application {
public static void main(String[] args) {
// //Object> Person>Student
// //Object> Person>Teacher
// //Object>String
// Object object = new Student();
// //System.out.println(X instanceof Y);//能不能编译通过!
//
//
// System.out.println(object instanceof Student);//true
// System.out.println(object instanceof Person);//true
// System.out.println(object instanceof Teacher);//false
// System.out.println(object instanceof String);//false
// System.out.println("===================================");
// Person person = new Student();
// System.out.println(person instanceof Student);//true
// System.out.println(person instanceof Person);//true
// System.out.println(person instanceof Object);//true
// System.out.println(person instanceof Teacher);//false
// //System.out.println(person instanceof String);//编译就报错
// System.out.println("===================================");
// Student student = new Student();
// System.out.println(student instanceof Student);//true
// System.out.println(student instanceof Person);//true
// System.out.println(student instanceof Object);//true
// //System.out.println(student instanceof Teacher);//编译就报错
//
//
//类型之间的转化:基本类型转换 高低(64、32、16、8)
//高转低强转,低转高,不需要
//类型之间的转化: 父 子 高-->低
Person student = new Student();
//student将这个对象转化为Student类型,我们就可以使用Student类型的方法了
((Student)student).go();
//子类转换为父类,可能会丢失自己本来的一些方法
Student student1 = new Student();
student1.go();
Person person = student;
}
类型转换
1、父类引用指向子类的对象
2、把子类转换为父类,向上转型,会丢失自己原来的一些方法
3、把父类转换为子类,向下转型,强制转换,才调用子类方法
4、方便方法的调用(转型),减少重复的代码,简洁。
抽象:
封装、继承、多态
抽象类、接口
static
- 静态变量可以直接用类名访问,也称类变量。
- 静态变量(或方法)对于类,所有对象(实例)所共享。
public class Student{
private static int age;//静态的变量
private double score;//非静态的变量
public void run2(){
}
public static void sing(){
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println(s1.score);
sing();
}
}
- 静态区代码 加载类时一起被初始化,最早执行且只执行一次(第一次new)。
package kuangshen.demo04;
public class Person {
//2、赋初始值
{
//代码块(匿名代码块)
System.out.println("匿名代码块");
}
//1、
static {
//静态代码块,类加载直接执行,永久执行一次
System.out.println("静态代码块");
}
//3、
public Person() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("================");
Person person2 = new Person();
}
}
/*
静态代码块
匿名代码块
构造方法
================
匿名代码块
构造方法
*/
- Math->随机数:
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
//第一种随机数,不用导包
System.out.println(Math.random()); //0.7562202902634543
//第二种随机数,静态导入包
System.out.println(random());
System.out.println(PI);
}
}
/*
0.15872988354589912
3.141592653589793
*/
抽象类(abstract)
- abstract修饰的类就是抽象类,修饰的方法就是抽象方法。
- 抽象类中可以没有抽象方法,但有抽象方法的类一定要声明为抽象类。
- 抽象类不能使用new来创建对象,它是用来让子类继承的。
- 抽象方法只有方法的声明,没有实现,让其子类实现。
- 子类继承抽象类,必须实现抽象类的所有方法,否则该子类也要声明为抽象类。
//abstract 抽象类:类 extends: 单继承(接口可以多继承)
public abstract class Action {
//约束~有人帮我们实现~
//abstract,抽象方法,只有方法名字,没有方法的实现!
public abstract void doSomething();
//1.不能new抽象类,只能靠子类去实现它,仅作为一个约束
//2.抽象方法只能出现在抽象类中,抽象类可以有普通方法
//抽象的抽象:约束
//3.抽象类有构造器,可以派生子类
//4.抽象类的意义:约束,提高开发效率。但是类只能单继承,所以有局限 用的不多
}
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法
public class A extends Action{
@Override
public void doSomething() {
}
}
接口(interface)
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范,没有方法实现,专业的约束!约束与实现分离:面向接口编程~
- 接口就是规范,定义的是一组规则,"你是什么…必须做什么…"的思想。
- 接口的本质是约束,就像人间法律一样,制定好大家都遵守。
//interface 定义的关键字,接口都需要有实现类
public interface UserService {
//接口中的所有定义其实都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
//类 可以实现接口 implements 接口
//实现接口的类,就需要重写接口中的方法
public class UserServiceImpl implements UserService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
}
精简:
//interface接口,接口都要有继承类
//实现类(implements 可以继承多个接口)
//多继承,利用接口实现多继承
public interface UserService {
//定义的属性都是常量,默认修饰 public static final
public static final int AGE = 99; //一般不用
//所有的定义的方法都是抽象的 默认public abstract
public abstract void run();
void add();
void query();
void delete();
}
作用:
1、约束
2、定义一些不同的方法,让不同人的实现
3、public abstact
4、public static final
5、接口没有构造方法,不能被实例化
6、实现类必须要重写接口中的方法
7、实现类(implements) 可以实现多个接口
内部类
- 内部类就是在一个类的内部再定义一个类,比如A类中定义了一个B类,那么B就是A的内部类,而A相对B来说就是外部类
1、成员内部类:可以操作外部类的私有属性及方法
2、静态内部类:static修饰,不能访问外部类私有属性
3、局部内部类:外部类的方法里定义的类
4、匿名内部类:没有名字初始化类
异常
运行时异常:
简单分类
- 检查型异常:最具代表性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如用户要打开一个不存在的文件时引发的异常,这些异常在编译时不能被简单地忽略。
- **运行时异常:**是可能被程序员避免的异常,与检查性异常相反,运行时异常可以在编译时忽略。
- **错误Error:**错误不是异常,而是脱离程序员控制的问题。错误在代码经常被忽略。例如当栈溢出,一个异常就发生了,它们在编译也检查不到。
异常体系结构
Error
运行时异常
捕获和抛出异常
注:finally 可以不要finally ,假设IO,资源,关闭!
- 抛出异常
- 捕获异常
- 异常处理关键字:try、catch、finally、throw、throws
public static void main(String[] args) {
int a = 1;
int b = 0;
try { //try监控区域
System.out.println(a/b);
}catch (ArithmeticException e){ //catch 捕获异常
System.out.println("程序出现异常,变量b不能为0");
}catch (Exception e){
e.printStackTrace();
}finally { //一定会执行,处理善后工作,如关闭资源
System.out.println("finally");
}
if(b==0){ //抛出异常一般在方法中使用
throw new ArithmeticException(); //主动抛出异常
}
}
//Ctrl+Alt+T 快捷键插入 try-catch
throw,throws区别
自定义异常
总结不易,不妨点个赞再走吧 :)