todas los atributos por defecto son de tipo publica, por lo que se puede llegar a ellos desde cualquier programa para obtener o alterar su valor.
Te equivocas, por defecto son de tipo "package", que significa que ese atributo (o metodos, si estos tampoco se declaran con public o private o protected) puede ser accedido desde cualquier clase que este dentro del mismo paquete. Una cosa curiosa del tipo de dato "package" es que la unica forma de declararlo como tal es omitiendo el tipo de acceso (public, private o protected, como ya he dicho). De modo que si no se escriben ninguna de estas 3 palabras solo entonces es package.
me gustaría saber porque se declaran de esta manera, y no de forma publica. Yo he llegado a la conclusión de que puede ser por seguir el paradigma, segmentar el programa, en métodos, pero no se si es por eso.
Lo normal no solo es declararlo de forma private los atributos sino ademas crear un metodo getAtributo() y setAtributo() para obtener el atributo y cambiar el valor del mismo.
Antes que nada tienes que entender que java es completamente POO, y la POO se hizo mas que nada para trabajar en equipo. Cada programador crea una clase de forma independiente y al final las combinan todas para formar el programa mas facilmente.
La idea mas que nada es la siguiente: Imaginate que en un proyecto ENORME se utiliza en muchiiisimos sitios un atributo de una clase. Ahora imaginate que, por alguna razon, cada vez que se accede a dicho atributo necesitas ejecutar una funcion o cambiar algunos datos de la misma clase. Si el atributo fuera publico esto seria un problemón, ya que tienes que adaptar el codigo de 300 clases en donde quiera que sea que se haya utilizado ese atributo para cada vez que lo haga hacer lo que sea que se tenga que hacer. Bueno pues si en vez de eso hicieras el atributo privado e hicieras los metodos getter y setter (asi es como se le llaman a los metodos setAtributo y getAtributo) entonces solamente tendrias que modificar el metodo getter y voilá, ya está hecho.
También es util para control de errores: supongamos que tienes un atributo de tipo int al que solo te interesa que se le de un valor entre 5 y 20. Entonces dentro del setter tendrias que mostrar un mensaje de error y terminar el programa si el valor que se le pasa por parametro no cumple la condicion de que esté entre 5 y 20. (No se si habrás visto el control de errores con el bloque try catch y los throw que sirven para controlar cuando se produce un error como meter un valor que no este entre 5 y 20 en este caso, pero lo suyo seria utilizar throw)