三元运算符

Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个数字:");
int a = scanner.nextInt();
System.out.println("请输入第二个数字:");
int b = scanner.nextInt();
System.out.println("请输入第三个数字:");
int c = scanner.nextInt();
System.out.println("下面输出上述的最大值,请稍等");
int temp =a>b?a:b;
int max = c>temp?c:temp;
System.out.println(max);

switch判断

public static void main(String[] args) {
int a = 10;
switch (a){
case 1:
System.out.println("111111");
break;
case 2:
System.out.println("22222222");
break;
case 10:
System.out.println("ni");
break;
default:
System.out.println("33333");
break;
}
}

匿名对象,所谓的匿名对象就是左边没有名字和赋值运算符,只有右边对象。

循环

计算水仙花数经典案例

public class ShuiXianHua {
//计算水仙花数
public static void main(String[] args) {
int d = 0;
for (int i = 100; i < 1000; i++) {
int a = i%10;
int b = i/10%10;
int c = i/100;
if (a * a * a + b * b * b + c * c * c == a + b * 10 + c * 100){
d++;
System.out.println(i); //输出水仙花类型
}
}
System.out.println(d); //输出符合水仙花的数值的总数
}
}
do…while循环,不管是否符合判断条件,都会执行一次
public class Demo01dowhile {
public static void main(String[] args) {
int a = 10;
do {
System.out.println(a);
a++;
}while (a<9);
}
}
增强for循环。for循环中的变量类型需要和数组元素类型一致
public static void main(String[] args) {
String[] str1 ={"123", "234", "e43"};
for (String s : str1) {
System.out.println(s);
}
}
}

java中单引号和双引号的区别:

单引号中是字符,双引号中是字符串

System.out.println("H"+"A"); //HA 拼接为HA字符串

System.out.println('H'+'a'); //169 H和a进行了加法运算2) 根据ASCII表H = 72和a = 97

构造方法是一种特殊的方法,作用就是创建对象。功能:主要完成对象数据的初始化

方法重载Overload(方法的名称一样,参数的列表不一样):

1.多个方法在同一个类中

2.参数个数不同

3.参数类型不同

4.参数类型顺序不同

方法的重写(覆写、覆盖)Override

重写发生在继承关系中,方法的名称一样,参数列表也一样。

特点:创建的是子类对象,则优先用子类的方法。

子类方法的返回值必须小于等于父类方法的返回值范围。

子类方法的权限必须大于等于父类方法的权限

例子

public class Phone {
public void call(){
System.out.println("打电话");
}
public void send(){
System.out.println("发短信");
}
public void show(){
System.out.println("显示号码");
}
}
public class NewPhone extends Phone {

@Override
public void show(){
super.show(); //super关键字
System.out.println("显示头像");
System.out.println("显示姓名");
}
}
public class DemoPhone {
public static void main(String[] args) {
Phone phone = new Phone();
phone.show();
phone.call();
phone.send();
System.out.println("================================");
NewPhone newPhone = new NewPhone();
newPhone.show();
newPhone.call();
newPhone.send();
}
结果:
显示号码
打电话
发短信
================================
显示号码
显示头像
显示姓名
打电话
发短信


数组:


数组反转案例

public class ArrReverse {

public static void main(String[] args) {
int[] arr = {18,23,34,667,564,1};
for (int start = 0,end=arr.length-1; start <=end; start++,end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] =temp;
}
printArray(arr);

}
public static void printArray(int[] arr){
System.out.print("[");
for (int x = 0; x <arr.length ; x++) {
if (x == arr.length - 1){
System.out.print(arr[x]);
}else {
System.out.print(arr[x]+",");
}
}
System.out.print("]");
}
}
public class Score {
//需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
//选手的最后得分为,去掉一个最高分和最低分之后剩下的4个平均值。

public static int[] getScore() {
int[] arrScore = new int[6];
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < 6; i++) {
System.out.println("请输入第"+(i+1)+"个评委的打分:");
arrScore[i] = scanner.nextInt();
}
System.out.print("[");
for (int i = 0; i < arrScore.length; i++) {
if (i < arrScore.length - 1) {
System.out.print(arrScore[i] + ",");
} else {
System.out.print(arrScore[i] + "]");
}
}
return arrScore;
}


//定义一个方法,得到数组中的最高分
public static int getMaxScore(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max = arr[i];
}
}
return max;
}
//定义一个方法,得到数组中的最低分
public static int getMinScore(int[] arr){
int min = arr[0];
for (int i = 0; i <arr.length ; i++) {
if (arr[i]<min){
min=arr[i];
}
}
return min;
}
//定义一个方法获取数组的平均分
public static int getAvgScroe(int[] arr){
int sum = 0;
int a = 0;
for (int i = 0; i <arr.length ; i++) {
int minScore = getMinScore(arr);
int maxScore = getMaxScore(arr);
if (arr[i]==minScore||arr[i]==maxScore){
sum = sum+0;
a = a+0;
}else {
sum = sum+arr[i];
a = a+1;
}
}
int avg = sum/a;
return avg;
}

public static void main(String[] args) {
int avg = getAvgScroe(getScore());
System.out.println("------------------------");
System.out.println(avg);
}


}

关于ArrayList:

1.ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素

2.常用例子

public class Demo05ArrayList {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
System.out.println(arrayList);
// arrayList.remove(1); //remove(索引值)
System.out.println(arrayList);
arrayList.get(1); //get(索引值)
System.out.println(arrayList);

}
}

字符串String

1.字符串的截取:左闭右开,substring(1,3)。括号中是索引值

2.统计不同类型字符出现次数经典案例

/**
* 键盘输入一个字符串,并且统计其中各种字符出现的次数
* 种类有:大写字母、小写字母、数字、其他
* 思路:1.键盘输入,sc.next()
* 2.String类型转换为字符串,toCharArray()
* 3.
*/
public class Demo07StringCount {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = scanner.next();

char[] array = str.toCharArray();//输出的是字符数组
int countUpper = 0;
int countLower = 0;
int countNum = 0;
int countOther = 0;
for (int i = 0; i < array.length; i++) {
if ('A'<=array[i]&&array[i]<='Z'){
countUpper++;
}else if ('a'<=array[i]&&array[i]<='z'){
countLower++;
}else if ('0'<=array[i]&&array[i]<='9'){
countNum++;
}else{
countOther++;
}
}
System.out.println("大写字母的个数是:"+countUpper);
System.out.println("小写字母的个数是:"+countLower);
System.out.println("数字个数是:"+countNum);
System.out.println("其他个数是:"+countOther);

}
}
//把随机字符串中的所有字符升序排列,并倒序打印
public class Demo02Arrays {
public static void main(String[] args) {
String s1 = "12ewra434f是我";
char[] chars = s1.toCharArray();
Arrays.sort(chars);
// System.out.println(chars);
for (int i = chars.length - 1; i >= 0; i--) {
System.out.println(chars[i]);
}
}
}

将字符串对象中的字符转换为一个字符数组

String和StringBuilder的区别:

String:内容是不可变的

StringBuilder:内容是可变的

String和StringBuilder之间的相互转换方法:

//将String类型的字符串转换成StringBuilder类型,使用StringBulider构造方法
String s = "hello";
StringBuilder sb = new StringBuilder(s);
System.out.println(s);
//将StringBuilder类型的字符串转换成String类型,使用toString方法即可
StringBuilder sb1 = new StringBuilder();
sb1.append("world");
String s1 = sb1.toString();
System.out.println(s1);


Math工具类的使用

//计算-10.8到5.9之间,绝对值大于6或者小于2.1的整数有多少个?
public class DemoMath01 {
public static void main(String[] args) {
double min = -10.8;
double max = 5.9;
int count = 0;
for (int i = (int) min; i <max ; i++) {
if (Math.abs(i)>6 || Math.abs(i)<2.1){
count++;
}
}
System.out.println(count);
}
}

静态static关键字描述

一旦使用了static关键字,那么这样的内容就不再属于自己,而是属于类的,所以凡是本类的对象,都共享同一份。

public class Person {
static {
System.out.println("静态代码块执行!!!");
}
public Person(){
System.out.println("构造方法执行!");
}
}
public class Demo04Static {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
}
执行结果如下:
静态代码块执行!!!
构造方法执行!
构造方法执行!
构造方法执行!

静态代码块仅会执行一次。

静态不能直接访问非静态。原因:因为在内存中先有的静态内容,后有的非静态内容。“先人不知道后人,但是后人知道先人”。

静态不能使用this。因为静态针对的是类,而不是具体的某一个对象

public class Student {
private String name;
private int age;
private int id;
private static int idCounter = 0; //可以作为学号计数器,每当new了一个对象的时候,计数器++

public Student() {
idCounter++;
}

public Student(String name, int age) {
this.name = name;
this.age = age;
this.id = ++idCounter;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public static void main(String[] args) {
Student student01 = new Student("cui", 12);
Student student02 = new Student("li", 15);
System.out.println("学生1的姓名:" + student01.getName() + ";"
+ "学生1的年龄:" + student01.getAge() + ";"
+ "学生1的学号:" + student01.id);
System.out.println("学生2的姓名:" + student02.getName() + ";"
+ "学生2的年龄:" + student02.getAge() + ";"
+ "学生2的学号:" + student02.id);
}
}
运行结果:
学生1的姓名:cui;学生1的年龄:12;学生1的学号:1
学生2的姓名:li;学生2的年龄:15;学生2的学号:2

区分子类方法中重名的三种变量


super关键字的使用

1.在子类的成员方法中,访问父类的成员变量。

super.num;

2.在子类的成员方法中,访问父类的成员方法。

super.method();

3.在子类的构造方法中,访问父类的构造方法。

public Zi(){

super();

}

this关键字的三种用法

this关键字是用来访问本类内容

1.在本类的方法中访问本类的成员变量

2、在本类的方法中访问本类的另一个成员方法

3、在本类的构造方法中访问本类的另一个构造方法

public class Zi extends Fu {
int num = 10;
public Zi(){
this(20); //在本类的构造方法中,访问本类的另一个构造方法。本类的无参构造,调用本类的有参构造
}
public Zi(int num){

}
public void showNum(){
int num = 20;
System.out.println(num); //输出局部变量20
System.out.println(this.num); //输出本类的成员变量10
System.out.println(super.num); //输出父类的成员变量6
}
public void methodA(){
System.out.println("AAA");
}
public void methodB(){
this.methodA();//在本类的成员方法中,访问本类的另一个成员方法
System.out.println("BBB");
}

}

抽象

抽象方法:就是在返回值之前加上abstract关键字,去掉大括号,直接分号结束。

抽象类:抽象方法所在的类必须是抽象类,就是在class之前加上abstract关键字。

public abstract class DemoAbstract01 {
// 这是一个抽象方法,代表吃东西,但是具体吃的是什么东西(大括号里的内容)不确定
public abstract void eat();
}

如何使用抽象方法和抽象类:

1、不能直接创建new抽象对象;

2、需要子类继承抽象父类;

3、子类需要覆盖重写父类当中所有的抽象方法。

覆盖重写:去掉abstract关键字,补上大括号

public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼,狗吃肉,奥特曼打小怪兽");
}
}

抽象类是对事物的抽象,接口是对行为的抽象。

接口相关知识

接口的抽象方法定义如下:

/**
* 注意事项:接口当中的抽象方法,修饰符必须是两个固定的关键字,public和abstract
* 这两个关键字修饰符,可以选择性的忽略
*/
public interface DemoInterface {
// 以下都是抽象方法
public abstract void methods0();

public void methods1();

abstract void methods2();

void methods3();
}

接口的使用步骤:

1.接口不能直接使用,必须有一个实现类来实现该接口

格式:

public class 实现类名 implements 接口名称{

//……………………

}

2.接口的实现类必须覆盖重写(实现)接口中的所有抽象方法,除非实现类是抽象类;

实现:去掉abstract关键字,加上大括号

3.创建实现类的对象,进行使用。

注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。正确方法是直接通过接口名.静态方法名(参数)

4.在java 9+的版本中,成员变量(其实就是常量)的定义如下:

public static final 数据类型 常量名称=值 ;常量名称必须是大写字母,多个需要下划线分割

例子:public static final int NUM_MY_AGE = 26;

5.接口中最重要的就是抽象方法

public abstract void method01(参数列表){

//方法体

}

6.从java8开始,接口里允许定义默认方法,格式是:

public default 返回值类型 方法名(参数列表){

//方法体

}

7.从java8开始,接口里允许定义静态方法,格式:

public static 返回值类型 方法名称(参数列表){

//方法体

}

注意:应该通过接口名称调用,不能通过实现类对象调用接口静态方法。

8.从java9开始,接口中允许定义私有方法。只有接口自己才可以调用,不能被实现或被别人使用

9.接口没有静态代码块或构造方法。

10、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB{

}

多态

父类引用指向子类对象就叫做多态。

格式:父类名称 对象名 = new 子类名称();

或者:接口名称 对象名 = new 实现类名称();

访问成员变量的两种方式:

1、直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有就向上找。

2、间接通过成员方法访问成员变量,看该方法属于谁, 优先用谁,没有就向上找。

成员变量:编译看左,运行看左

System.out.println(cat1.age);//age的取值是看父类中age的取值

在多态当中成员方法的访问规则是:

编译看左,运行看右

System.out.println(cat1.eat());//看父类中有没有eat()方法,运行是看子类中eat()方法内容

对象的向上转型其实就是多态写法:

Animal animal = new Cat();

含义:右侧创建了一个子类对象,把它当做父类来看待。创建了一只猫,把这猫当动物。

多态

多态:

1、有继承或实现关系

2、方法重写

3、父类引用指向子类对象

多态中成员访问特点

1、访问成员变量:编译看左,运行看左

2、访问成员方法:编译看左,运行看右

多态的好处和弊端

1、提高了程序的扩展功能

具体的体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作

2、但是不能访问子类特有的特性

final关键字

final修饰的类不可以被继承;

内部类

1.成员内部类

成员内部类的定义格式:

public class 类名称{

public class 类名称{

}

}

Map集合

map集合是双列集合,常用的方法如下:

新建一个map集合对象

map<String,String> map = new HashMap<>();

向map集合中添加元素

map.put("键","值")

根据键取值

String value = map.get("key")

根据键删除值

String value = map.remove("key")

遍历map集合

首先将集合中的key放到一个set集合中,然后根据key值进行遍历value值

例子

①根据增强for进行遍历

Set<String> keys = map.keySet();

for(String key:keys){

String value = map.get(key);

}

②使用迭代器进行遍历

Set<String> keys = map.keySet();

Iterator<String> iterator = keys.iterator();

while (iterator.hasNext()){

String key = iterator.next();

String value = map.get(key);

System.out.println(value);

}

map集合遍历键值对的方式

当map集合一创建,就会在map集合中创建Entry对象,用来记录键与值的映射关系

public class mapEntry {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("小明",123);
map.put("小红",193);
map.put("小丽",333);
//使用map集合中的entrySet()方法将map集合中多个Entry对象取出来放到Set集合中
Set<Map.Entry<String, Integer>> entries = map.entrySet();
//使用迭代器进行遍历
Iterator<Map.Entry<String, Integer>> it = entries.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key);
System.out.println(value);
}
}
}

HashMap和LinkedHashMap区别:

key都不可以重复

HashMap取的时候无序

LinkedHashMap取的时候按照存的顺序

经典案例分析

题目:统计一个字符串中字符出现的次数

分析:1.获取一个字符串,键盘输入

2.(使用map集合)遍历字符串中的字符并判断是否在map集合中已存在,若存在,则value值+1,否则新增key,并且value值设置为1

import java.util.*;

public class CharCount {
public static void main(String[] args) {
System.out.println("请输入一串字符串:");
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
// 获取到每一个字符
char[] array = s.toCharArray();
HashMap<Character,Integer> map = new HashMap<>();
// 遍历每一个字符
for (int i = 0; i < array.length; i++) {
// 判断该字符是否存在map集合中
boolean b = map.containsKey(array[i]);
// 如果存在,则value值+1
if (b==true){
Integer value = map.get(array[i]);
value++;
// 把新的value存储到map集合中
map.put(array[i],value);
}else{
// 若不存在,则把key值存储到map集合中,并设置value值为1
map.put(array[i],1);
}

}
// 遍历map集合。下面使用的是迭代器遍历
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
Iterator<Map.Entry<Character, Integer>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<Character, Integer> entry = iterator.next();
Character key = entry.getKey();
Integer val = entry.getValue();
System.out.println(key);
System.out.println(val);
}



}
}

子父类异常的处理:

1、如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者不抛出异常。

2、父类方法没有抛出异常,子类重写父类方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出

注意:父类异常是什么样子,子类异常就是什么样子

自定义异常:

/**
* 自定义异常类,java提供的异常类不够我们使用,所以需要自己定义
* 格式 public class XXXException extends Exception |RuntimeException{
* 添加一个空参的构造方法
* 添加一个带异常信息的构造方法
* }
*/
public class RegisterException extends Exception{
public RegisterException(){

}
public RegisterException(String message){
super(message);
}
}

自定义异常案例:

import java.util.Scanner;

/**
* 模拟注册操作,如果用户名已存在,则抛出异常提示:亲,该用户名已被注册
* 分析
* 1.首先需要把已有的用户名放到一个数组中
* 2.键盘输入输入的用户名
*/
public class RegisterExceptionDemo {
static String[] tel = {"13800000001", "13800000002", "13800000003"};

public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户注册手机号:");
// 输入注册手机号
String new_tel = scanner.next();
checkUserTel(new_tel);
}
public static void checkUserTel(String new_tel) {
for (String exist_tel : tel) {
if (exist_tel.equals(new_tel)){
try {
throw new RegisterException("亲,该用户名已被注册");
} catch (RegisterException e) {
e.printStackTrace();
}
return;
// return的作用就是结束方法
}
}
System.out.println("注册成功");
}
}

多线程

并发:两个或多个事件在同一时间段内发生(交替发生)

并行:两个或多个事件在同一时刻发生

进程:进入到内存中的应用程序

线程:一个进程可以包含多个线程(比如电脑管家中有清理垃圾、病毒查杀、电脑加速等)

创建多线程的步骤:

//创建一个Thread类的子类
public class MyThread extends Thread {
// 重写Thread的run方法,目的就是设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run"+i);
}
}
}
/**
* 创建多线程的步骤
* 1、创建一个Thread类的子类
* 2、在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)
* 3、创建Thread类的子类对象
* 4、调用Thread类的方法start方法,开启新的线程,执行run方法
*/
public class Demo01Thread {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main"+i);
}
}
}

创建多线程的第二种方法:

/**
* 创建多线程的第二种方法:实现Runnable接口
* 步骤如下:
* 1.创建一个Runnable接口的实现类
* 2、在实现类中重写run方法,设置线程任务
* 3、创建一个Runnable接口的实现类对象
* 4、创建Thread类对象,构造方法中传递Runnable接口的实现类对象
* 5.调用Thread类中的start方法,开启新的线程执行run方法
*/
public class Demo01Runnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class RunnableObject {
public static void main(String[] args) {

Demo01Runnable runnable = new Demo01Runnable();
Thread t = new Thread(runnable);
t.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}

Thread和Runnable的区别:

如果一个类继承Thread则不适合资源共享,但是如果实现了Runnable接口的话,则很容易实现资源共享。

实现Runnable接口比继承Thread类所具有的优势:

1.适合多个相同的程序代码的线程去共享同一资源

2.可以避免java中的单继承的局限性(一个类只能继承一个类,一个类继承了Thread类就不能继承其他的类,如果实现了Runnable接口,还可以继承其他的类,实现其他接口)

3.增加程序的健壮性、实现解耦合操作,代码可以被多个线程共享,代码和线程独立

4、线程池只能放入实现Runnable或Callable类线程,不能直接放入继承Thread的类


获取线程名称的方式:

public class Demo02Thread {
public static void main(String[] args) {
MyThread01 myThread01 = new MyThread01();
myThread01.start();
new MyThread01().start();
new MyThread01().start();
}
}
public class MyThread01 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}

匿名内部类实现线程的创建

匿名:没有名字

内部类:写在其他类内部的类

匿名内部类的作用:简化代码

把子类继承父类,重写父类方法,创建子类对象合一步完成

把实现类实现接口,重写接口中的方法,创建实现类对象合成一步完成

匿名内部类的最终产物:

子类/实现类对象,而这个类没有名字

格式:

new 父类/接口(){

重写父类/接口中的方法

}.start()

解决线程安全问题

为了保证每个线程都能正常执行原子操作,java引入了线程同步机制

有三种方式完成同步操作:

1.同步代码块

2.同步方法

3.锁机制

1.同步代码块

格式

synchronized (锁对象){
可能会出现线程安全的代码(访问了共享数据的代码)
}

注意:

1.同步代码块中的对象可以是任意的对象

2.必须保证多个线程使用的锁对象是同一个

3.锁对象作用:

把同步代码块锁住,只让一个线程在同步代码块中执行

//卖票案例
public class Ticket implements Runnable{
private int ticket = 100;
//创建一个对象
Object object = new Object();
@Override
public void run() {
while (true){
synchronized (object){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket--;
}
}
}
}
}
public class DemoTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread01 = new Thread(ticket);
Thread thread02 = new Thread(ticket);
Thread thread03 = new Thread(ticket);
thread01.start();
thread02.start();
thread03.start();
}
}

2.同步方法

格式:

修饰符 synchronized 返回值类型 方法名(参数列表){

}

3.lock锁

lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁操作